<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/M.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/M.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/M.png">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib/pace/pace-theme-minimal.min.css">
  <script src="/lib/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"maureen-liu.gitee.io","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":"valine","storage":true,"lazyload":false,"nav":null,"activeClass":"valine"},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="1、设计模式简介  1.1 目标  理解松耦合设计思想 掌握面向对象设计原则 掌握重构技法改善设计 掌握GOF 核心设计模式   1.2 什么是设计模式  每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。这样，你就能一次又一次地使用该方案而不必做重复劳动。 ​																																																	——Chr">
<meta property="og:type" content="article">
<meta property="og:title" content="C++设计模式">
<meta property="og:url" content="https://maureen-liu.gitee.io/p/9725cb23.html">
<meta property="og:site_name" content="Maureen&#39;s blog">
<meta property="og:description" content="1、设计模式简介  1.1 目标  理解松耦合设计思想 掌握面向对象设计原则 掌握重构技法改善设计 掌握GOF 核心设计模式   1.2 什么是设计模式  每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。这样，你就能一次又一次地使用该方案而不必做重复劳动。 ​																																																	——Chr">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211143649357.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211143742684.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151342958.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151407697.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151714187.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151740739.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151804770.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213160414002.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213162328458.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213163605233.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214145215333.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214150930329.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214111213675.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214111534980.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214111825656.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214112025783.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211215175435380.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214112347840.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214113257215.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214114417809.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214114916095.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216155412868.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214142853300.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214143334978.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214143441838.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214144111911.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216182623494.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216184709433.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216185906831.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216192351521.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211218122357202.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211218122448277.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219114054727.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219115720763.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219124009451.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219124115233.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219131404423.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211221145219708.png">
<meta property="article:published_time" content="2021-12-11T06:25:41.000Z">
<meta property="article:modified_time" content="2021-12-21T07:25:34.719Z">
<meta property="article:author" content="Maureen">
<meta property="article:tag" content="李建忠">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211143649357.png">

<link rel="canonical" href="https://maureen-liu.gitee.io/p/9725cb23.html">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>
<script src="/lib/fireworks.js"></script>
  <title>C++设计模式 | Maureen's blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Maureen's blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">记录学习的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://maureen-liu.gitee.io/p/9725cb23.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/stan.jpeg">
      <meta itemprop="name" content="Maureen">
      <meta itemprop="description" content="心之所向，素履以往">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Maureen's blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          C++设计模式
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2021-12-11 14:25:41" itemprop="dateCreated datePublished" datetime="2021-12-11T14:25:41+08:00">2021-12-11</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-12-21 15:25:34" itemprop="dateModified" datetime="2021-12-21T15:25:34+08:00">2021-12-21</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/" itemprop="url" rel="index"><span itemprop="name">C++</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" itemprop="url" rel="index"><span itemprop="name">设计模式</span></a>
                </span>
            </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/p/9725cb23.html#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/p/9725cb23.html" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>75k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>1:09</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
      
      
        <h1 id="1-设计模式简介"><a class="markdownIt-Anchor" href="#1-设计模式简介"></a> 1、设计模式简介</h1>
<h2 id="11-目标"><a class="markdownIt-Anchor" href="#11-目标"></a> 1.1 目标</h2>
<ul>
<li>理解松耦合设计思想</li>
<li>掌握面向对象设计原则</li>
<li>掌握重构技法改善设计</li>
<li>掌握GOF 核心设计模式</li>
</ul>
<h2 id="12-什么是设计模式"><a class="markdownIt-Anchor" href="#12-什么是设计模式"></a> 1.2 什么是设计模式</h2>
<blockquote>
<p>每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。这样，你就能一次又一次地使用该方案而不必做重复劳动。</p>
<p>​																																																	——Christopher Alexander</p>
</blockquote>
<span id="more"></span>
<h2 id="13-gof设计模式"><a class="markdownIt-Anchor" href="#13-gof设计模式"></a> 1.3 GOF设计模式</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211143649357.png" alt="image-20211211143649357"></p>
<h2 id="14-从面向对象谈起"><a class="markdownIt-Anchor" href="#14-从面向对象谈起"></a> 1.4 从面向对象谈起</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211143742684.png" alt="image-20211211143742684"></p>
<h2 id="15-深入理解面向对象"><a class="markdownIt-Anchor" href="#15-深入理解面向对象"></a> 1.5 深入理解面向对象</h2>
<ul>
<li>向下：深入理解三大面向对象机制
<ul>
<li>封装，隐藏内部实现</li>
<li>继承，复用现有代码</li>
<li>多态，改写对象行为</li>
</ul>
</li>
<li>向上：深刻把握面向对象机制所带来的抽象意义，理解如何使用这些机制来表达现实世界，掌握什么是“好的面向对象设计”</li>
</ul>
<h2 id="16-软件设计固有的复杂性"><a class="markdownIt-Anchor" href="#16-软件设计固有的复杂性"></a> 1.6 软件设计固有的复杂性</h2>
<blockquote>
<p>建筑商从来不会去想给一栋已建好100层高的楼房底下再新修一个小地下室——这样做花费极大而且注定要失败。然而令人惊奇的是，软件系统的用户在要求做出类似改变时却不会仔细考虑，而且他们认为这只是需要简单编程的事。</p>
<p>​																																						—— Object-Oriented Analysis and Design with Applications</p>
</blockquote>
<h2 id="17-软件设计复杂的根本原因"><a class="markdownIt-Anchor" href="#17-软件设计复杂的根本原因"></a> 1.7 软件设计复杂的根本原因</h2>
<ul>
<li>变化
<ul>
<li>客户需求的变化</li>
<li>技术平台的变化</li>
<li>开发团队的变化</li>
<li>市场环境的变化</li>
<li>…</li>
</ul>
</li>
</ul>
<h2 id="18-如何解决复杂性"><a class="markdownIt-Anchor" href="#18-如何解决复杂性"></a> 1.8 如何解决复杂性？</h2>
<ul>
<li>分解
<ul>
<li>人们面对复杂性有一个常见的做法：即分而治之，将大问题分解为多个小问题，将复杂问题分解为多个简单问题。</li>
</ul>
</li>
<li>抽象
<ul>
<li>更高层次来讲，人们处理复杂性有一个通用的技术，即抽象。由于不能掌握全部的复杂对象，我们选择忽视它的非本质细节，而去处理泛化和理想化了的对象模型。</li>
</ul>
</li>
</ul>
<h2 id="19-结构化-vs-面向对象"><a class="markdownIt-Anchor" href="#19-结构化-vs-面向对象"></a> 1.9 结构化 VS. 面向对象</h2>
<p>分解：伪码</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Shape1.h</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Point</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">int</span> x;</span><br><span class="line">    <span class="keyword">int</span> y;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Line</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Point start;</span><br><span class="line">    Point end;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">Line</span>(<span class="keyword">const</span> Point&amp; start, <span class="keyword">const</span> Point&amp; end) &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;start = start;</span><br><span class="line">        <span class="keyword">this</span>-&gt;end = end;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Rect</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Point leftUp;</span><br><span class="line">    <span class="keyword">int</span> width;</span><br><span class="line">    <span class="keyword">int</span> height;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">Rect</span>(<span class="keyword">const</span> Point&amp; leftUp, <span class="keyword">int</span> width, <span class="keyword">int</span> height) &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;leftUp = leftUp;</span><br><span class="line">        <span class="keyword">this</span>-&gt;width = width;</span><br><span class="line">        <span class="keyword">this</span>-&gt;height = height;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//增加</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Circle</span>&#123;</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form &#123;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    Point p1;</span><br><span class="line">    Point p2;</span><br><span class="line"> </span><br><span class="line">    vector&lt;Line&gt; lineVector;</span><br><span class="line">    vector&lt;Rect&gt; rectVector;</span><br><span class="line">    <span class="comment">//改变</span></span><br><span class="line">    vector&lt;Circle&gt; circleVector;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MainForm</span>()&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">OnMouseDown</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">OnMouseUp</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">OnPaint</span><span class="params">(<span class="keyword">const</span> PaintEventArgs&amp; e)</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MainForm::OnMouseDown</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>&#123;</span><br><span class="line">    p1.x = e.X;</span><br><span class="line">    p1.y = e.Y;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    Form::<span class="built_in">OnMouseDown</span>(e);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MainForm::OnMouseUp</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>&#123;</span><br><span class="line">    p2.x = e.X;</span><br><span class="line">    p2.y = e.Y;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (rdoLine.Checked)&#123;</span><br><span class="line">        <span class="function">Line <span class="title">line</span><span class="params">(p1, p2)</span></span>;</span><br><span class="line">        lineVector.<span class="built_in">push_back</span>(line);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (rdoRect.Checked)&#123;</span><br><span class="line">        <span class="keyword">int</span> width = <span class="built_in">abs</span>(p2.x - p1.x);</span><br><span class="line">        <span class="keyword">int</span> height = <span class="built_in">abs</span>(p2.y - p1.y);</span><br><span class="line">        <span class="function">Rect <span class="title">rect</span><span class="params">(p1, width, height)</span></span>;</span><br><span class="line">        rectVector.<span class="built_in">push_back</span>(rect);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//改变</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (...)&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        circleVector.<span class="built_in">push_back</span>(circle);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    <span class="keyword">this</span>-&gt;<span class="built_in">Refresh</span>();</span><br><span class="line"> </span><br><span class="line">    Form::<span class="built_in">OnMouseUp</span>(e);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MainForm::OnPaint</span><span class="params">(<span class="keyword">const</span> PaintEventArgs&amp; e)</span></span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//针对直线</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; lineVector.<span class="built_in">size</span>(); i++)&#123;</span><br><span class="line">        e.Graphics.<span class="built_in">DrawLine</span>(Pens.Red,</span><br><span class="line">            lineVector[i].start.x, </span><br><span class="line">            lineVector[i].start.y,</span><br><span class="line">            lineVector[i].end.x,</span><br><span class="line">            lineVector[i].end.y);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//针对矩形</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; rectVector.<span class="built_in">size</span>(); i++)&#123;</span><br><span class="line">        e.Graphics.<span class="built_in">DrawRectangle</span>(Pens.Red,</span><br><span class="line">            rectVector[i].leftUp,</span><br><span class="line">            rectVector[i].width,</span><br><span class="line">            rectVector[i].height);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//改变</span></span><br><span class="line">    <span class="comment">//针对圆形</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; circleVector.<span class="built_in">size</span>(); i++)&#123;</span><br><span class="line">        e.Graphics.<span class="built_in">DrawCircle</span>(Pens.Red,</span><br><span class="line">            circleVector[i]);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    Form::<span class="built_in">OnPaint</span>(e);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>抽象：伪码</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Shape2.h</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Shape</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Draw</span><span class="params">(<span class="keyword">const</span> Graphics&amp; g)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Shape</span>() &#123; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Point</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">int</span> x;</span><br><span class="line">    <span class="keyword">int</span> y;</span><br><span class="line">&#125;;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Line</span>:</span> <span class="keyword">public</span> Shape&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Point start;</span><br><span class="line">    Point end;</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">Line</span>(<span class="keyword">const</span> Point&amp; start, <span class="keyword">const</span> Point&amp; end)&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;start = start;</span><br><span class="line">        <span class="keyword">this</span>-&gt;end = end;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//实现自己的Draw，负责画自己</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Draw</span><span class="params">(<span class="keyword">const</span> Graphics&amp; g)</span></span>&#123;</span><br><span class="line">        g.<span class="built_in">DrawLine</span>(Pens.Red, start.x, start.y,end.x, end.y);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Rect</span>:</span> <span class="keyword">public</span> Shape&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Point leftUp;</span><br><span class="line">    <span class="keyword">int</span> width;</span><br><span class="line">    <span class="keyword">int</span> height;</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">Rect</span>(<span class="keyword">const</span> Point&amp; leftUp, <span class="keyword">int</span> width, <span class="keyword">int</span> height)&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;leftUp = leftUp;</span><br><span class="line">        <span class="keyword">this</span>-&gt;width = width;</span><br><span class="line">        <span class="keyword">this</span>-&gt;height = height;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//实现自己的Draw，负责画自己</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Draw</span><span class="params">(<span class="keyword">const</span> Graphics&amp; g)</span></span>&#123;</span><br><span class="line">        g.<span class="built_in">DrawRectangle</span>(Pens.Red, leftUp, width, height);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;;</span><br><span class="line"> </span><br><span class="line"><span class="comment">//增加</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Circle</span> :</span> <span class="keyword">public</span> Shape&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//实现自己的Draw，负责画自己</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Draw</span><span class="params">(<span class="keyword">const</span> Graphics&amp; g)</span></span>&#123;</span><br><span class="line">        g.<span class="built_in">DrawCircle</span>(Pens.Red, ...);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form &#123;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    Point p1;</span><br><span class="line">    Point p2;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//针对所有形状</span></span><br><span class="line">    vector&lt;Shape*&gt; shapeVector; <span class="comment">//此处必须要放Shape*指针，保证多态性</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MainForm</span>()&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">OnMouseDown</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">OnMouseUp</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">OnPaint</span><span class="params">(<span class="keyword">const</span> PaintEventArgs&amp; e)</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MainForm::OnMouseDown</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>&#123;</span><br><span class="line">    p1.x = e.X;</span><br><span class="line">    p1.y = e.Y;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    Form::<span class="built_in">OnMouseDown</span>(e);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MainForm::OnMouseUp</span><span class="params">(<span class="keyword">const</span> MouseEventArgs&amp; e)</span></span>&#123;</span><br><span class="line">    p2.x = e.X;</span><br><span class="line">    p2.y = e.Y;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (rdoLine.Checked)&#123;</span><br><span class="line">        shapeVector.<span class="built_in">push_back</span>(<span class="keyword">new</span> <span class="built_in">Line</span>(p1,p2));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (rdoRect.Checked)&#123;</span><br><span class="line">        <span class="keyword">int</span> width = <span class="built_in">abs</span>(p2.x - p1.x);</span><br><span class="line">        <span class="keyword">int</span> height = <span class="built_in">abs</span>(p2.y - p1.y);</span><br><span class="line">        shapeVector.<span class="built_in">push_back</span>(<span class="keyword">new</span> <span class="built_in">Rect</span>(p1, width, height));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//改变</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (...)&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        shapeVector.<span class="built_in">push_back</span>(circle);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    <span class="keyword">this</span>-&gt;<span class="built_in">Refresh</span>();</span><br><span class="line"> </span><br><span class="line">    Form::<span class="built_in">OnMouseUp</span>(e);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MainForm::OnPaint</span><span class="params">(<span class="keyword">const</span> PaintEventArgs&amp; e)</span></span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//针对所有形状</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; shapeVector.<span class="built_in">size</span>(); i++)&#123;</span><br><span class="line"> </span><br><span class="line">        shapeVector[i]-&gt;<span class="built_in">Draw</span>(e.Graphics); <span class="comment">//多态调用，各负其责</span></span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    Form::<span class="built_in">OnPaint</span>(e);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>代码中注释了“改变/增加”的是有新需求的情况设计到要修改的代码。</p>
<p>分解的做法不容易复用，而抽象的设计方法的代码复用非常高，能够使用通用的方法统一处理。</p>
<h2 id="110-软件设计的目标"><a class="markdownIt-Anchor" href="#110-软件设计的目标"></a> 1.10 软件设计的目标</h2>
<p>什么是好的软件设计？软件设计的金科玉律：<mark>复用！</mark></p>
<h1 id="2-面向对象设计原则"><a class="markdownIt-Anchor" href="#2-面向对象设计原则"></a> 2、面向对象设计原则</h1>
<h2 id="21-面向对象设计为什么"><a class="markdownIt-Anchor" href="#21-面向对象设计为什么"></a> 2.1 面向对象设计，为什么？</h2>
<p>变化是复用的天敌！</p>
<p>面向对象设计最大的优势在于：<mark>抵御变化</mark>！</p>
<h2 id="22-重新认识面向对象"><a class="markdownIt-Anchor" href="#22-重新认识面向对象"></a> 2.2 重新认识面向对象</h2>
<ul>
<li>理解隔离变化
<ul>
<li>从宏观层面来看，面向对象的构建方式更能适应软件的变化，能将变化所带来的影响减为最小</li>
</ul>
</li>
<li>各司其职
<ul>
<li>从微观层面来看，面向对象的方式更强调各个类的“责任”</li>
<li>由于需求变化导致的新增类型不应该影响原来类型的实现——是所谓各负其责</li>
</ul>
</li>
<li>对象是什么？
<ul>
<li>从语言实现层面来看，对象封装了代码和数据。</li>
<li>从规格层面讲，对象是一系列可被使用的公共接口。</li>
<li>从概念层面讲，对象是某种拥有责任的抽象。</li>
</ul>
</li>
</ul>
<h2 id="23-面向对象设计原则"><a class="markdownIt-Anchor" href="#23-面向对象设计原则"></a> 2.3 面向对象设计原则</h2>
<h3 id="231-依赖倒置原则dip"><a class="markdownIt-Anchor" href="#231-依赖倒置原则dip"></a> 2.3.1 依赖倒置原则（DIP)</h3>
<ul>
<li>高层模块（稳定）不依赖于低层模块（变化），二者都应该依赖于抽象（稳定）</li>
<li>抽象（稳定）不应该依赖于实现细节（变化），实现细节应该依赖于抽象（稳定）</li>
</ul>
<p>举例说明：第1章中的demo里，<code>MainForm</code>是高层模块，<code>Line</code> 和 <code>Rect</code>是底层模块，<code>Shape</code>是抽象。</p>
<p>”分解“的方案里，<code>MainForm</code>依赖了<code>Line</code>和<code>Rect</code>，<code>Line</code>和<code>Rect</code>是容易变化的，就会导致<code>MainForm</code>也跟着变化；而在&quot;抽象&quot;的方案里，<code>MainForm</code>依赖于<code>Shape</code>，<code>Line</code>和<code>Rect</code>也依赖于<code>Shape</code>，只有<code>Line</code>和<code>Rect</code>变化，<code>Shape</code>和<code>MainForm</code>基本稳定，这就遵循了DIP原则。</p>
<h3 id="232-开放封闭原则ocp"><a class="markdownIt-Anchor" href="#232-开放封闭原则ocp"></a> 2.3.2 开放封闭原则（OCP）</h3>
<ul>
<li>对扩展开放，对更改封闭</li>
<li>类模块应该是可扩展的，但是不可修改</li>
</ul>
<h3 id="233-单一职责原则srp"><a class="markdownIt-Anchor" href="#233-单一职责原则srp"></a> 2.3.3 单一职责原则（SRP)</h3>
<ul>
<li>一个类应该仅有一个引起它变化的原因</li>
<li>变化的方向隐含着类的责任</li>
</ul>
<h3 id="234-liskov-替换原则lsp"><a class="markdownIt-Anchor" href="#234-liskov-替换原则lsp"></a> 2.3.4 Liskov 替换原则（LSP)</h3>
<ul>
<li>子类必须能够替换它们的基类（IS-A）</li>
<li>继承表达类型抽象</li>
</ul>
<h3 id="235-接口隔离原则isp"><a class="markdownIt-Anchor" href="#235-接口隔离原则isp"></a> 2.3.5 接口隔离原则（ISP)</h3>
<ul>
<li>不应该强迫客户程序依赖它们不用的方法</li>
<li>接口应该小而完备</li>
</ul>
<h3 id="236-优先使用对象组合而不是类继承"><a class="markdownIt-Anchor" href="#236-优先使用对象组合而不是类继承"></a> 2.3.6 优先使用对象组合，而不是类继承</h3>
<ul>
<li>类继承通常为“白箱复用”，对象组合通常为“黑箱复用”</li>
<li>继承在某种程度上破坏了封装性，子类父类耦合度高</li>
<li>而对象组合则只要求被组合的对象具有良好定义的接口，耦合度低</li>
</ul>
<h3 id="237-封装变化点"><a class="markdownIt-Anchor" href="#237-封装变化点"></a> 2.3.7 封装变化点</h3>
<ul>
<li>使用封装来创建对象之间的分界层，让设计者可以在分界层的一侧进行修改，而不会对另一层产生不良的影响，从而实现层次间的松耦合</li>
</ul>
<h3 id="238-针对接口编程而不是针对实现编程"><a class="markdownIt-Anchor" href="#238-针对接口编程而不是针对实现编程"></a> 2.3.8 针对接口编程，而不是针对实现编程</h3>
<ul>
<li>不将变量类型声明为某个特定的具体类，而是声明为某个接口</li>
<li>客户程序无需获知对象的具体类型，只需要知道对象所具有的接口</li>
<li>减少系统中各部分的依赖关系，从而实现“高内聚、松耦合”的类型设计方案</li>
</ul>
<h2 id="24-面向接口设计"><a class="markdownIt-Anchor" href="#24-面向接口设计"></a> 2.4 面向接口设计</h2>
<p>产业强盛的标志：<span style="font-size:30px;color:red">接口标准化</span></p>
<h2 id="25-以史为鉴"><a class="markdownIt-Anchor" href="#25-以史为鉴"></a> 2.5 以史为鉴</h2>
<p>秦为什么能够统一六国？</p>
<p>据史书记载和考古发现，秦的兵器不论东西南北，出土地点都有统一的标准，包括剑、戈、弩，甚至弩机、弩体、箭头都是一样的，而其他六国则不是。</p>
<p>毕升的活字印刷为什么成为四大发明，推动了人类文明的前进？</p>
<p>毕升之前的雕版印刷将字刻死在木板或石板上，每次印刷不同文章，要刻不同的版。而毕升发明的活字印刷首先在板上刻好字格，然后再刻单独的字模。印刷时，将活的字模“按需索取”放在字格中，不同的排列方法产生不同的文章，而不必重新刻版。</p>
<h2 id="26-将设计原则提升为设计经验"><a class="markdownIt-Anchor" href="#26-将设计原则提升为设计经验"></a> 2.6 将设计原则提升为设计经验</h2>
<ol>
<li>设计习语 Design Idioms
<ul>
<li>Design Idioms 描述与特定编程语言相关的低层模式，技巧，惯用法。</li>
</ul>
</li>
<li>设计模式 Design Patterns
<ul>
<li>Design Patterns主要描述的是“类与相互通信的对象之间的组织关系“，包括它们的角色、职责、协作方式等方面</li>
</ul>
</li>
<li>架构模式 Architectural Patterns
<ul>
<li>Architectural Patterns描述系统中与基本结构组织关系密切的高层模式，包括子系统划分，职责，以及如何组织它们之间关系的规则</li>
</ul>
</li>
</ol>
<h1 id="3-模式的分类"><a class="markdownIt-Anchor" href="#3-模式的分类"></a> 3、模式的分类</h1>
<h2 id="31-gof-23-模式分类"><a class="markdownIt-Anchor" href="#31-gof-23-模式分类"></a> 3.1 GOF-23 模式分类</h2>
<ul>
<li>从目的来看：
<ul>
<li>创建型（Creational）模式：将对象的部分创建工作延迟到子类或者其他对象，从而应对需求变化为对象创建时具体类型实现引来的冲击。</li>
<li>结构型（Structural）模式：通过类继承或者对象组合获得更灵活的结构，从而应对需求变化为对象的结构带来的冲击。</li>
<li>行为型（Behavioral）模式：通过类继承或者对象组合来划分类与对象间的职责，从而应对需求变化为多个交互的对象带来的冲击。</li>
</ul>
</li>
<li>从范围来看：
<ul>
<li>类模式处理类与子类的静态关系。【注：偏重于继承方案】</li>
<li>对象模式处理对象间的动态关系。【注：偏重于组合方案】</li>
</ul>
</li>
</ul>
<h2 id="32-从封装变化角度对模式分类"><a class="markdownIt-Anchor" href="#32-从封装变化角度对模式分类"></a> 3.2 从封装变化角度对模式分类</h2>
<ul>
<li>组件协作：
<ul>
<li>Template Method</li>
<li>Observer / Event</li>
<li>Strategy</li>
</ul>
</li>
<li>单一职责：
<ul>
<li>Decorator</li>
<li>Bridge</li>
</ul>
</li>
<li>对象创建:
<ul>
<li>Factory Method</li>
<li>Abstract Factory</li>
<li>Prototype</li>
<li>Builder</li>
</ul>
</li>
<li>对象性能：
<ul>
<li>Singleton</li>
<li>Flyweight</li>
</ul>
</li>
<li>接口隔离:
<ul>
<li>Façade</li>
<li>Proxy</li>
<li>Mediator</li>
<li>Adapter</li>
</ul>
</li>
<li>状态变化：
<ul>
<li>Memento</li>
<li>State</li>
</ul>
</li>
<li>数据结构：
<ul>
<li>Composite</li>
<li>Iterator</li>
<li>Chain of Resposibility</li>
</ul>
</li>
<li>行为变化：
<ul>
<li>Command</li>
<li>Visitor</li>
</ul>
</li>
<li>领域问题：
<ul>
<li>Interpreter</li>
</ul>
</li>
</ul>
<h2 id="33-重构获得模式-refactoring-to-patterns"><a class="markdownIt-Anchor" href="#33-重构获得模式-refactoring-to-patterns"></a> 3.3 重构获得模式 Refactoring to Patterns</h2>
<ul>
<li>面向对象设计模式是“好的面向对象设计”，所谓“好的面向对象设计”指是那些可以满足“应对变化，提高复用”的设计。</li>
<li>现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点，然后在变化点处应用设计模式，从而来更好地应对需求的变化”。”什么时候、什么地点应用设计模式”比“理解设计模式结构本身”更为重要。</li>
<li>设计模式的应用不宜先入为主，一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。敏捷软件开发实践提倡的“Refactoring to Patterns”是目前普遍公认的最好的使用设计模式的方法。</li>
</ul>
<h2 id="34-推荐图书"><a class="markdownIt-Anchor" href="#34-推荐图书"></a> 3.4 推荐图书</h2>
<img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151342958.png" alt="image-20211213151342958" style="zoom:67%;">
<h2 id="35-重构关键技法"><a class="markdownIt-Anchor" href="#35-重构关键技法"></a> 3.5 重构关键技法</h2>
<img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151407697.png" alt="image-20211213151407697" style="zoom:50%;">
<h1 id="4-组件协作模式"><a class="markdownIt-Anchor" href="#4-组件协作模式"></a> 4、&quot;组件协作&quot;模式</h1>
<ul>
<li>现代软件专业分工之后的第一个结果是“框架与应用程序的划分”，“组件协作”模式通过晚期绑定，来实现框架与应用程序之间的松耦合，是二者之间协作时常用的模式。</li>
<li>典型模式
<ul>
<li>Template Method</li>
<li>Strategy</li>
<li>Observer / Event</li>
</ul>
</li>
</ul>
<h2 id="41-template-method模式"><a class="markdownIt-Anchor" href="#41-template-method模式"></a> 4.1 Template Method模式</h2>
<h3 id="411-动机motivation"><a class="markdownIt-Anchor" href="#411-动机motivation"></a> 4.1.1 动机(Motivation)</h3>
<ul>
<li>在软件构建过程中，对于某一项任务，它常常有<mark>稳定</mark>的整体操作结构，但各个子步骤却有很多<mark>改变</mark>的需求，或者由于固有的原因（比如框架与应用之间的关系）而无法和任务的整体结构同时实现。</li>
<li>如何在确定<mark>稳定</mark>操作结构的前提下，来灵活应对各个子步骤的变化或者晚期实现需求？</li>
</ul>
<h3 id="412-结构化软件设计流程"><a class="markdownIt-Anchor" href="#412-结构化软件设计流程"></a> 4.1.2 结构化软件设计流程</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//template1_lib.cpp</span></span><br><span class="line"><span class="comment">//程序库开发人员</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Library</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step1</span><span class="params">()</span> </span>&#123; </span><br><span class="line">        <span class="comment">//... </span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step3</span><span class="params">()</span> </span>&#123; </span><br><span class="line">        <span class="comment">//... </span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step5</span><span class="params">()</span> </span>&#123; </span><br><span class="line">        <span class="comment">//... </span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//template1_app.cpp</span></span><br><span class="line"><span class="comment">//应用程序开发人员</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Application</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">Step2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step4</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="function">Library <span class="title">lib</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function">Application <span class="title">app</span><span class="params">()</span></span>;</span><br><span class="line">    </span><br><span class="line">    lib.<span class="built_in">Step1</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (app.<span class="built_in">Step2</span>()) &#123;</span><br><span class="line">        lib.<span class="built_in">Step3</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">        app.<span class="built_in">Step4</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    lib.<span class="built_in">Step5</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151714187.png" alt="image-20211213151714187" style="zoom:50%;">
<h3 id="413-面向对象软件设计流程"><a class="markdownIt-Anchor" href="#413-面向对象软件设计流程"></a> 4.1.3 面向对象软件设计流程</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//template2_lib.cpp</span></span><br><span class="line"><span class="comment">//程序库开发人员</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Library</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//稳定 template method</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">Step1</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">Step2</span>()) &#123; <span class="comment">//支持变化==&gt; 虚函数的多态调用</span></span><br><span class="line">            <span class="built_in">Step3</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="built_in">Step4</span>(); <span class="comment">//支持变化==&gt; 虚函数的多态调用</span></span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="built_in">Step5</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//基类中的析构函数要写成虚函数，否则delete的时候的调用不到子类的析构函数</span></span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Library</span>() &#123; &#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step1</span><span class="params">()</span> </span>&#123; <span class="comment">//稳定</span></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step3</span><span class="params">()</span> </span>&#123; <span class="comment">//稳定</span></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Step5</span><span class="params">()</span> </span>&#123; <span class="comment">//稳定</span></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Step2</span><span class="params">()</span> </span>= <span class="number">0</span>; <span class="comment">//变化</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Step4</span><span class="params">()</span> </span>= <span class="number">0</span>; <span class="comment">//变化</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//template2_app.cpp</span></span><br><span class="line"><span class="comment">//应用开发人员</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Application</span> :</span> <span class="keyword">public</span> Library &#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Step2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//... 子类重写实现</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Step4</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//... 子类重写实现</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//规范的</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Library* pLib = <span class="keyword">new</span> <span class="built_in">Application</span>(); <span class="comment">//pLib是个多态指针</span></span><br><span class="line">    pLib-&gt;<span class="built_in">Run</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">delete</span> pLib; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151740739.png" alt="image-20211213151740739" style="zoom:50%;">
<h3 id="414-早绑定与晚绑定"><a class="markdownIt-Anchor" href="#414-早绑定与晚绑定"></a> 4.1.4 早绑定与晚绑定</h3>
<p>【注：结构化软件设计的流程是一种早绑定的写法，Library写的比Application早，写得比较晚的调用实现比较早的程序就叫做早绑定；面向对象软件设计的流程是一种晚绑定的写法，Library反过来调用Application，实现的比较早的调用实现比较晚的就叫做晚绑定；】</p>
<img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213151804770.png" alt="image-20211213151804770" style="zoom:50%;">
<h3 id="415-模式定义"><a class="markdownIt-Anchor" href="#415-模式定义"></a> 4.1.5 模式定义</h3>
<blockquote>
<p>定义一个操作中的算法的骨架(稳定)，而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。</p>
<p>​																																																														——《设计模式》GoF</p>
</blockquote>
<p>【注：此处的“骨架”对应于上面的第二种写法中的<code>Run</code>，“延迟到子类”的意思就是定义虚函数让子类去实现或重写，就是支持子类来变化。</p>
<p>第二种写法中的模板方法就是<code>Run</code>，它是相对稳定的，但是它其中又包含了变化（Step2和Step4）。如果极端地讨论，全部是稳定的或者全部是变化的都不适合使用设计模式。</p>
<p>模式应用的核心就是分辨出变化和稳定。】</p>
<h3 id="416-结构"><a class="markdownIt-Anchor" href="#416-结构"></a> 4.1.6 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213160414002.png" alt="image-20211213160414002"></p>
<p><code>AbstractClass</code>中的<code>TemplateMethod()</code>是稳定的，*<code>PrimitiveOperationX()</code>*是变化的。设计模式的学习重点就是区分开“稳定”和“变化”的部分。</p>
<p>对应到之前的代码实现：<code>AbstractClass</code>就是<code>Library</code>类；<code>TemplateMethod()</code>就是<code>Run()</code>方法；<em><code>PrimitiveOperation1()</code></em> 对应于 <code>Step2()</code>方法； <em><code>PrimitiveOperation2()</code></em> 对应于 <code>Step4()</code> 方法；<code>ConcreteClass</code>就是<code>Application</code>类；</p>
<h3 id="417-要点总结"><a class="markdownIt-Anchor" href="#417-要点总结"></a> 4.1.7 要点总结</h3>
<ul>
<li>Template Method模式是一种<mark>非常基础性</mark>的设计模式，在面向对象系统中有着大量的应用。它用最简洁的机制（虚函数的多态性）为很多应用程序框架提供了灵活的<mark>扩展点</mark>【注：扩展点就是继承+虚函数】，是代码复用方面的基本实现结构。</li>
<li>除了可以灵活应对子步骤的变化外，==“不要调用我，让我来调用你”==的<em>反向控制结构</em> 是Template Method的典型应用。</li>
<li>在具体实现方面，被Template Method 调用的虚方法可以具有实现，也可以没有任何实现（抽象方法、纯虚方法），但一般推荐将它们设置为 protected 方法。</li>
</ul>
<h2 id="42-strategy-策略模式"><a class="markdownIt-Anchor" href="#42-strategy-策略模式"></a> 4.2 Strategy 策略模式</h2>
<h3 id="421-动机motivation"><a class="markdownIt-Anchor" href="#421-动机motivation"></a> 4.2.1 动机（Motivation）</h3>
<ul>
<li>在软件构建过程中，某些对象使用的算法可能多种多样，经常改变，如果将这些算法都编码到对象中，将会使对象变得异常复杂；而且有时候支持不使用的算法也是一个性能负担。</li>
<li>如何在运行时根据需要透明地更改对象的算法？将算法与对象本身解耦，从而避免上述问题？</li>
</ul>
<h3 id="422-模式定义"><a class="markdownIt-Anchor" href="#422-模式定义"></a> 4.2.2 模式定义</h3>
<blockquote>
<p>定义一系列算法，把它们一个个封装起来，并且使它们可互相替换（变化）。该模式使得算法可独立于使用它的客户程序(稳定)而变化（扩展，子类化）。</p>
<p>​																																																															——《设计模式》GoF</p>
</blockquote>
<h3 id="423-代码示例"><a class="markdownIt-Anchor" href="#423-代码示例"></a> 4.2.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//strategy1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">TaxBase</span> &#123;</span></span><br><span class="line">	CN_Tax,</span><br><span class="line">	US_Tax,</span><br><span class="line">	DE_Tax,</span><br><span class="line">	FR_Tax       <span class="comment">//更改</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SalesOrder</span>&#123;</span></span><br><span class="line">    TaxBase tax;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">double</span> <span class="title">CalculateTax</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (tax == CN_Tax)&#123;</span><br><span class="line">            <span class="comment">//CN***********</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (tax == US_Tax)&#123;</span><br><span class="line">            <span class="comment">//US***********</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (tax == DE_Tax)&#123;</span><br><span class="line">            <span class="comment">//DE***********</span></span><br><span class="line">        &#125;</span><br><span class="line">		<span class="keyword">else</span> <span class="keyword">if</span> (tax == FR_Tax)&#123;  <span class="comment">//更改</span></span><br><span class="line">			<span class="comment">//...</span></span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//....</span></span><br><span class="line">     &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//说明：这种方式更改的时候违反了开放封闭原则</span></span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//strategy2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TaxStrategy</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">double</span> <span class="title">Calculate</span><span class="params">(<span class="keyword">const</span> Context&amp; context)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">TaxStrategy</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//规范的写法是每个类放在不同的文件中</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CNTax</span> :</span> <span class="keyword">public</span> TaxStrategy&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">double</span> <span class="title">Calculate</span><span class="params">(<span class="keyword">const</span> Context&amp; context)</span></span>&#123;</span><br><span class="line">        <span class="comment">//***********</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">USTax</span> :</span> <span class="keyword">public</span> TaxStrategy&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">double</span> <span class="title">Calculate</span><span class="params">(<span class="keyword">const</span> Context&amp; context)</span></span>&#123;</span><br><span class="line">        <span class="comment">//***********</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DETax</span> :</span> <span class="keyword">public</span> TaxStrategy&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">double</span> <span class="title">Calculate</span><span class="params">(<span class="keyword">const</span> Context&amp; context)</span></span>&#123;</span><br><span class="line">        <span class="comment">//***********</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//扩展：正常应该是在一个新的文件中写，此处只是为了方便演示</span></span><br><span class="line"><span class="comment">//*********************************</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FRTax</span> :</span> <span class="keyword">public</span> TaxStrategy&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">double</span> <span class="title">Calculate</span><span class="params">(<span class="keyword">const</span> Context&amp; context)</span></span>&#123;</span><br><span class="line">		<span class="comment">//.........</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SalesOrder</span>&#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    TaxStrategy* strategy; <span class="comment">//抽象类，必须放一个指针，而且具有多态性</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">SalesOrder</span>(StrategyFactory* strategyFactory)&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;strategy = strategyFactory-&gt;<span class="built_in">NewStrategy</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">SalesOrder</span>()&#123;</span><br><span class="line">        <span class="keyword">delete</span> <span class="keyword">this</span>-&gt;strategy;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">CalculateTax</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        <span class="function">Context <span class="title">context</span><span class="params">()</span></span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">double</span> val = </span><br><span class="line">            strategy-&gt;<span class="built_in">Calculate</span>(context); <span class="comment">//多态调用</span></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//说明：这种方式扩展的时候遵循了开放封闭原则</span></span><br></pre></td></tr></table></figure>
<p>复用指的是编译后二进制意义的复用，而不是简单的代码片段的复用。<code>SalesOrder</code>是稳定的，各种<code>XXTax</code> 是变化的。</p>
<h3 id="424-结构"><a class="markdownIt-Anchor" href="#424-结构"></a> 4.2.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213162328458.png" alt="image-20211213162328458"></p>
<p>【注：<code>Context</code>和<code>Strategy</code> 是稳定的，<code>ConcreteStrategyX</code> 是变化的】</p>
<h3 id="425-要点总结"><a class="markdownIt-Anchor" href="#425-要点总结"></a> 4.2.5 要点总结</h3>
<ul>
<li>Strategy及其子类为组件提供了一系列可重用的算法，从而可以使得类型在<mark>运行时</mark>方便地根据需要在各个算法之间进行切换。</li>
<li>Strategy模式提供了用条件判断语句以外的另一种选择，消除条件判断语句，就是在解耦合。<mark>含有许多条件判断语句的代码通常都需要Strategy模式</mark>。【注：绝对稳定不变的情况可以用if-else，如一周七天，而其他的可能变化条件判断的情况就要用Strategy模式。代码示例中的第一种写法的很多条件判断代码可能根本不会执行，但是却被迫装载到了CPU高级缓存中，占用了缓存位置，其他代码可能被挤出高级缓存，不得不装载到硬盘；而第二种写法则不会有这个问题，减轻了性能负担，但这不是Strategy模式的最大优势，Strategy模式的最大优势是用扩展应对变化。看到条件判断的情况，都要考虑能不能使用<code>Strategy</code>模式。】</li>
<li>如果Strategy对象没有实例变量，那么各个上下文可以共享同一个Strategy对象，从而节省对象开销。【注：一般可以使用单例模式】</li>
</ul>
<h2 id="43-observer-观察者模式"><a class="markdownIt-Anchor" href="#43-observer-观察者模式"></a> 4.3 Observer 观察者模式</h2>
<h3 id="431-动机motivation"><a class="markdownIt-Anchor" href="#431-动机motivation"></a> 4.3.1 动机（Motivation）</h3>
<ul>
<li>在软件构建过程中，我们需要为某些对象建立一种“通知依赖关系”——一个对象（目标对象）的状态发生改变，所有的依赖对象（观察者对象）都将得到通知。如果这样的依赖关系过于紧密，将使软件不能很好地抵御变化。</li>
<li>使用面向对象技术，可以将这种依赖关系弱化，并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。</li>
</ul>
<h3 id="432-模式定义"><a class="markdownIt-Anchor" href="#432-模式定义"></a> 4.3.2 模式定义</h3>
<blockquote>
<p>定义对象间的一种一对多（变化）的依赖关系，以便当一个对象(Subject)的状态发生改变时，所有依赖于它的对象都得到通知并自动更新。</p>
<p>​																																										 ——《设计模式》GoF</p>
</blockquote>
<h3 id="433-代码示例"><a class="markdownIt-Anchor" href="#433-代码示例"></a> 4.3.3 代码示例</h3>
<p>实现一个文件分割器</p>
<p>第一种方案：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FileSplitter1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileSplitter</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	string m_filePath;</span><br><span class="line">	<span class="keyword">int</span> m_fileNumber;</span><br><span class="line">	ProgressBar* m_progressBar; <span class="comment">//注：ProgressBar是实现细节，容易变化。 是个通知控件</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="built_in">FileSplitter</span>(<span class="keyword">const</span> string&amp; filePath, <span class="keyword">int</span> fileNumber, ProgressBar* progressBar) :</span><br><span class="line">		<span class="built_in">m_filePath</span>(filePath), </span><br><span class="line">		<span class="built_in">m_fileNumber</span>(fileNumber),</span><br><span class="line">		<span class="built_in">m_progressBar</span>(progressBar)&#123;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">split</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="comment">//1.读取大文件</span></span><br><span class="line"></span><br><span class="line">		<span class="comment">//2.分批次向小文件中写入</span></span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; m_fileNumber; i++)&#123;</span><br><span class="line">			<span class="comment">//...</span></span><br><span class="line">			<span class="keyword">float</span> progressValue = m_fileNumber;</span><br><span class="line">			progressValue = (i + <span class="number">1</span>) / progressValue;</span><br><span class="line">			m_progressBar-&gt;<span class="built_in">setValue</span>(progressValue); <span class="comment">//更新进度条</span></span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line">	ProgressBar* progressBar;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line"></span><br><span class="line">		<span class="function">FileSplitter <span class="title">splitter</span><span class="params">(filePath, number, progressBar)</span></span>;</span><br><span class="line"></span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>存在的问题：违背了DIP原则，如果A依赖于B——编译时“依赖”，即A编译的时候B要存在。</p>
<p>重构使得遵循DIP原则：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FileSplitter1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IProgress</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DoProgress</span><span class="params">(<span class="keyword">float</span> value)</span></span>=<span class="number">0</span>;</span><br><span class="line">	<span class="keyword">virtual</span> ~<span class="built_in">IProgress</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileSplitter</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	string m_filePath;</span><br><span class="line">	<span class="keyword">int</span> m_fileNumber;</span><br><span class="line">	<span class="comment">//ProgressBar* m_progressBar; //注：ProgressBar是实现细节，容易变化。 是个通知控件</span></span><br><span class="line">	IProgress* m_iprogress;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="built_in">FileSplitter</span>(<span class="keyword">const</span> string&amp; filePath, <span class="keyword">int</span> fileNumber, IProgress* iprogress;) :</span><br><span class="line">		<span class="built_in">m_filePath</span>(filePath), </span><br><span class="line">		<span class="built_in">m_fileNumber</span>(fileNumber),</span><br><span class="line">		<span class="built_in">m_iprogress</span>(iprogress)&#123;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">split</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="comment">//1.读取大文件</span></span><br><span class="line"></span><br><span class="line">		<span class="comment">//2.分批次向小文件中写入</span></span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; m_fileNumber; i++)&#123;</span><br><span class="line">			<span class="comment">//...</span></span><br><span class="line">			<span class="keyword">float</span> progressValue = m_fileNumber;</span><br><span class="line">			progressValue = (i + <span class="number">1</span>) / progressValue;</span><br><span class="line">			m_iprogress-&gt;<span class="built_in">DoProgress</span>(progressValue); <span class="comment">//更新进度条</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form, <span class="keyword">public</span> IProgress</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line">	ProgressBar* progressBar;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line">		<span class="function">FileSplitter <span class="title">splitter</span><span class="params">(filePath, number, <span class="keyword">this</span>)</span></span>;</span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DoProgress</span><span class="params">(<span class="keyword">float</span> value)</span> </span>&#123;</span><br><span class="line">        progressBar-&gt;<span class="built_in">setValue</span>(value);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>进一步的小优化：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FileSplitter1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IProgress</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DoProgress</span><span class="params">(<span class="keyword">float</span> value)</span></span>=<span class="number">0</span>;</span><br><span class="line">	<span class="keyword">virtual</span> ~<span class="built_in">IProgress</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileSplitter</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	string m_filePath;</span><br><span class="line">	<span class="keyword">int</span> m_fileNumber;</span><br><span class="line">	<span class="comment">//ProgressBar* m_progressBar; //注：ProgressBar是实现细节，容易变化。 是个通知控件</span></span><br><span class="line">	IProgress* m_iprogress;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="built_in">FileSplitter</span>(<span class="keyword">const</span> string&amp; filePath, <span class="keyword">int</span> fileNumber, IProgress* iprogress;) :</span><br><span class="line">		<span class="built_in">m_filePath</span>(filePath), </span><br><span class="line">		<span class="built_in">m_fileNumber</span>(fileNumber),</span><br><span class="line">		<span class="built_in">m_iprogress</span>(iprogress)&#123;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">split</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="comment">//1.读取大文件</span></span><br><span class="line"></span><br><span class="line">		<span class="comment">//2.分批次向小文件中写入</span></span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; m_fileNumber; i++)&#123;</span><br><span class="line">			<span class="comment">//...</span></span><br><span class="line">			<span class="keyword">float</span> progressValue = m_fileNumber;</span><br><span class="line">			progressValue = (i + <span class="number">1</span>) / progressValue;</span><br><span class="line">			<span class="built_in">onProgress</span>(progressValue); </span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">onProgress</span><span class="params">(<span class="keyword">float</span> value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (m_iprogress != <span class="literal">nullptr</span>) &#123;</span><br><span class="line">            m_iprogress-&gt;<span class="built_in">DoProgress</span>(value);<span class="comment">//更新进度条</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>目前的实现只能支持一个观察者，此处就是<code>MainForm</code>。</p>
<p>修改使得支持多个观察者：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FileSplitter2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IProgress</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DoProgress</span><span class="params">(<span class="keyword">float</span> value)</span></span>=<span class="number">0</span>;</span><br><span class="line">	<span class="keyword">virtual</span> ~<span class="built_in">IProgress</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileSplitter</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	string m_filePath;</span><br><span class="line">	<span class="keyword">int</span> m_fileNumber;</span><br><span class="line"></span><br><span class="line">	List&lt;IProgress*&gt;  m_iprogressList; <span class="comment">// 抽象通知机制，支持多个观察者</span></span><br><span class="line">	</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="built_in">FileSplitter</span>(<span class="keyword">const</span> string&amp; filePath, <span class="keyword">int</span> fileNumber) :</span><br><span class="line">		<span class="built_in">m_filePath</span>(filePath), </span><br><span class="line">		<span class="built_in">m_fileNumber</span>(fileNumber)&#123;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">split</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">		<span class="comment">//1.读取大文件</span></span><br><span class="line"></span><br><span class="line">		<span class="comment">//2.分批次向小文件中写入</span></span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; m_fileNumber; i++)&#123;</span><br><span class="line">			<span class="comment">//...</span></span><br><span class="line"></span><br><span class="line">			<span class="keyword">float</span> progressValue = m_fileNumber;</span><br><span class="line">			progressValue = (i + <span class="number">1</span>) / progressValue;</span><br><span class="line">			<span class="built_in">onProgress</span>(progressValue);<span class="comment">//发送通知</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">addIProgress</span><span class="params">(IProgress* iprogress)</span></span>&#123;</span><br><span class="line">		m_iprogressList.<span class="built_in">add</span>(iprogress);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">removeIProgress</span><span class="params">(IProgress* iprogress)</span></span>&#123;</span><br><span class="line">		m_iprogressList.<span class="built_in">remove</span>(iprogress);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">onProgress</span><span class="params">(<span class="keyword">float</span> value)</span></span>&#123;</span><br><span class="line">		List&lt;IProgress*&gt;::iterator itor = m_iprogressList.<span class="built_in">begin</span>();</span><br><span class="line">		<span class="keyword">while</span> (itor != m_iprogressList.<span class="built_in">end</span>() )</span><br><span class="line">			(*itor)-&gt;<span class="built_in">DoProgress</span>(value); <span class="comment">//更新进度条</span></span><br><span class="line">			itor++;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form, <span class="keyword">public</span> IProgress</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line"></span><br><span class="line">	ProgressBar* progressBar;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line"></span><br><span class="line">		ConsoleNotifier cn;</span><br><span class="line"></span><br><span class="line">		<span class="function">FileSplitter <span class="title">splitter</span><span class="params">(filePath, number)</span></span>;</span><br><span class="line"></span><br><span class="line">		splitter.<span class="built_in">addIProgress</span>(<span class="keyword">this</span>); <span class="comment">//订阅通知</span></span><br><span class="line">		splitter.<span class="built_in">addIProgress</span>(&amp;cn)； <span class="comment">//订阅通知</span></span><br><span class="line"></span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line"></span><br><span class="line">		splitter.<span class="built_in">removeIProgress</span>(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DoProgress</span><span class="params">(<span class="keyword">float</span> value)</span></span>&#123;</span><br><span class="line">		progressBar-&gt;<span class="built_in">setValue</span>(value);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConsoleNotifier</span> :</span> <span class="keyword">public</span> IProgress &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DoProgress</span><span class="params">(<span class="keyword">float</span> value)</span></span>&#123;</span><br><span class="line">		cout &lt;&lt; <span class="string">&quot;.&quot;</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="433-结构"><a class="markdownIt-Anchor" href="#433-结构"></a> 4.3.3 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211213163605233.png" alt="image-20211213163605233"></p>
<p>【注：<code>Observer</code>对应于<code>IProgress</code>，<code>Update()</code>对应于<code>DoProgress()</code>，<code>Attach</code>对应于<code>addIProgress</code>，<code>Detach</code>对应于<code>removeIProgress</code>，<code>Notify</code>对应于<code>onProgress</code>, GOF中建议将这三个方法提出来放到一个父类中，其他的Subject继承它，但是此处我们没有将它提出来，<code>ConcreteSubject</code>就是<code>FileSplitter</code>，<code>ConcreteObserver</code>对应于<code>MainForm</code>和<code>ConsoleNotifier</code>，具体的观察者。</p>
<p>稳定的：<em><code>Subject</code></em>、<em><code>Observer</code></em></p>
<p>变化的：<code>ConcreteSubject</code>、<code>ConcreteObserver</code></p>
<p>】</p>
<h3 id="435-要点总结"><a class="markdownIt-Anchor" href="#435-要点总结"></a> 4.3.5 要点总结</h3>
<ul>
<li>使用面向对象的抽象，Observer模式使得我们可以<mark>独立地改变</mark>目标与观察者，从而使二者之间的依赖关系达致松耦合。</li>
<li>目标发送通知时，无需指定观察者，通知（可以携带通知信息作为参数）会自动传播。</li>
<li>观察者自己决定是否需要订阅通知，目标对象对此一无所知。</li>
<li>Observer模式是基于事件的UI框架中非常常用的设计模式，也是MVC模式的一个重要组成部分。</li>
</ul>
<h1 id="5-单一职责模式"><a class="markdownIt-Anchor" href="#5-单一职责模式"></a> 5、&quot;单一职责&quot;模式</h1>
<ul>
<li>在软件组件的设计中，如果责任划分的不清晰，使用继承得到的结果往往是随着需求的变化，子类急剧膨胀，同时充斥着重复代码，这时候的关键是划清责任。</li>
<li>典型模式
<ul>
<li>Decorator</li>
<li>Bridge</li>
</ul>
</li>
</ul>
<h2 id="51-decorator-装饰模式"><a class="markdownIt-Anchor" href="#51-decorator-装饰模式"></a> 5.1 Decorator 装饰模式</h2>
<h3 id="511-动机motivation"><a class="markdownIt-Anchor" href="#511-动机motivation"></a> 5.1.1 动机（Motivation）</h3>
<ul>
<li>在某些情况下我们可能会“过度地使用继承来扩展对象的功能”，由于继承为类型引入的静态特质，使得这种扩展方式缺乏灵活性；并且随着子类的增多（扩展功能的增多），各种子类的组合（扩展功能的组合）会导致更多子类的膨胀。</li>
<li>如何使“对象功能的扩展”能够根据需要来动态地实现？同时避免“扩展功能的增多”带来的子类膨胀问题？从而使得任何“功能扩展变化”所导致的影响将为最低？</li>
</ul>
<h3 id="512-模式定义"><a class="markdownIt-Anchor" href="#512-模式定义"></a> 5.1.2 模式定义</h3>
<blockquote>
<p>动态（组合）地给一个对象增加一些额外的职责。就增加功能而言，Decorator模式比生成子类（继承）更为灵活（消除重复代码 &amp; 减少子类个数）。</p>
<p>​																																																										——《设计模式》GoF</p>
</blockquote>
<h3 id="513-代码示例"><a class="markdownIt-Anchor" href="#513-代码示例"></a> 5.1.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//decorator1.cpp</span></span><br><span class="line"><span class="comment">//业务操作</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Stream</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>：</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Stream</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//主体类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileStream</span>:</span> <span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写文件流</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NetworkStream</span> :</span><span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MemoryStream</span> :</span><span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//扩展操作</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CryptoFileStream</span> :</span><span class="keyword">public</span> FileStream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">       </span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        FileStream::<span class="built_in">Read</span>(number);<span class="comment">//读文件流  静态特质，确定了只能调FileStream</span></span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        FileStream::<span class="built_in">Seek</span>(position);<span class="comment">//定位文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(byte data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        FileStream::<span class="built_in">Write</span>(data);<span class="comment">//写文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CryptoNetworkStream</span> :</span> :<span class="keyword">public</span> NetworkStream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        NetworkStream::<span class="built_in">Read</span>(number);<span class="comment">//读网络流 静态特质，确定了只能调NetworkStream</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        NetworkStream::<span class="built_in">Seek</span>(position);<span class="comment">//定位网络流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(byte data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        NetworkStream::<span class="built_in">Write</span>(data);<span class="comment">//写网络流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CryptoMemoryStream</span> :</span> <span class="keyword">public</span> MemoryStream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        MemoryStream::<span class="built_in">Read</span>(number);<span class="comment">//读内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        MemoryStream::<span class="built_in">Seek</span>(position);<span class="comment">//定位内存流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(byte data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        MemoryStream::<span class="built_in">Write</span>(data);<span class="comment">//写内存流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BufferedFileStream</span> :</span> <span class="keyword">public</span> FileStream&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BufferedNetworkStream</span> :</span> <span class="keyword">public</span> NetworkStream&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BufferedMemoryStream</span> :</span> <span class="keyword">public</span> MemoryStream&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CryptoBufferedFileStream</span> :</span><span class="keyword">public</span> FileStream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        <span class="comment">//额外的缓冲操作...</span></span><br><span class="line">        FileStream::<span class="built_in">Read</span>(number);<span class="comment">//读文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        <span class="comment">//额外的缓冲操作...</span></span><br><span class="line">        FileStream::<span class="built_in">Seek</span>(position);<span class="comment">//定位文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        <span class="comment">//额外的缓冲操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(byte data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        <span class="comment">//额外的缓冲操作...</span></span><br><span class="line">        FileStream::<span class="built_in">Write</span>(data);<span class="comment">//写文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        <span class="comment">//额外的缓冲操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Process</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//编译时装配</span></span><br><span class="line">    CryptoFileStream *fs1 = <span class="keyword">new</span> <span class="built_in">CryptoFileStream</span>();</span><br><span class="line">    BufferedFileStream *fs2 = <span class="keyword">new</span> <span class="built_in">BufferedFileStream</span>();</span><br><span class="line">    CryptoBufferedFileStream *fs3 =<span class="keyword">new</span> <span class="built_in">CryptoBufferedFileStream</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>涉及到的结构：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214145215333.png" alt="image-20211214145215333"></p>
<p>类的规模为：<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>1</mn><mo>+</mo><mi>n</mi><mo>+</mo><mi>n</mi><mo>×</mo><mi>m</mi><mo stretchy="false">!</mo><mtext> </mtext><mi mathvariant="normal">/</mi><mtext> </mtext><mn>2</mn></mrow><annotation encoding="application/x-tex">1 + n + n \times m! \ / \ 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">m</span><span class="mclose">!</span><span class="mspace"> </span><span class="mord">/</span><span class="mspace"> </span><span class="mord">2</span></span></span></span></p>
<p>这份代码存在冗余，加密操作都是相同的，代码大量的重复。</p>
<p>重构：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//decorator2.cpp</span></span><br><span class="line"><span class="comment">//业务操作</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Stream</span>&#123;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>：</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Stream</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//主体类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileStream</span>:</span> <span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写文件流</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NetworkStream</span> :</span><span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MemoryStream</span> :</span><span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//扩展操作，继承自Stream，是为了符合虚函数的接口规范</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CryptoStream</span>:</span> <span class="keyword">public</span> Stream &#123;</span><br><span class="line">    </span><br><span class="line">    Stream* stream;<span class="comment">//...new FileStream() / new NetworkStream() /...</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">CryptoStream</span>(Stream* stm) : <span class="built_in">stream</span>(stm)&#123;</span><br><span class="line">    </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">       </span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        stream-&gt;<span class="built_in">Read</span>(number);<span class="comment">//读文件流   动态特质，在运行时确定stream的具体类型</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        stream::<span class="built_in">Seek</span>(position);<span class="comment">//定位文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(byte data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        stream::<span class="built_in">Write</span>(data);<span class="comment">//写文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BufferedStream</span> :</span> <span class="keyword">public</span> Stream&#123;</span><br><span class="line">    </span><br><span class="line">    Stream* stream;<span class="comment">//...</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">BufferedStream</span>(Stream* stm) : <span class="built_in">stream</span>(stm)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Process</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//运行时装配</span></span><br><span class="line">    FileStream* s1=<span class="keyword">new</span> <span class="built_in">FileStream</span>();</span><br><span class="line">    CryptoStream* s2=<span class="keyword">new</span> <span class="built_in">CryptoStream</span>(s1); </span><br><span class="line">    BufferedStream* s3=<span class="keyword">new</span> <span class="built_in">BufferedStream</span>(s1);</span><br><span class="line">    BufferedStream* s4=<span class="keyword">new</span> <span class="built_in">BufferedStream</span>(s2);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>修改后的优点：将“继承”改成“对象组合&quot;，使用多态，在运行时确定具体类型，“编译时装配&quot;变成了&quot;运行时装配”。</p>
<p>将相同字段提到一个新的基类<code>DecoratorStream</code> 中：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//decorator3.cpp</span></span><br><span class="line"><span class="comment">//业务操作</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Stream</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>：</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Stream</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//主体类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileStream</span>:</span> <span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写文件流</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NetworkStream</span> :</span><span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写网络流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MemoryStream</span> :</span><span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">        <span class="comment">//读内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//定位内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(<span class="keyword">char</span> data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//写内存流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//扩展操作</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DecoratorStream</span>:</span> <span class="keyword">public</span> Stream&#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    Stream* stream;<span class="comment">//...</span></span><br><span class="line">    </span><br><span class="line">    <span class="built_in">DecoratorStream</span>(Stream* stm) : <span class="built_in">stream</span>(stm)&#123;</span><br><span class="line">    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CryptoStream</span>:</span> <span class="keyword">public</span> DecoratorStream &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">CryptoStream</span>(Stream* stm): <span class="built_in">DecoratorStream</span>(stm) &#123;</span><br><span class="line">    </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">char</span> <span class="title">Read</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</span><br><span class="line">       </span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        stream-&gt;<span class="built_in">Read</span>(number);<span class="comment">//读文件流</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Seek</span><span class="params">(<span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        stream::<span class="built_in">Seek</span>(position);<span class="comment">//定位文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Write</span><span class="params">(byte data)</span></span>&#123;</span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">        stream::<span class="built_in">Write</span>(data);<span class="comment">//写文件流</span></span><br><span class="line">        <span class="comment">//额外的加密操作...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BufferedStream</span> :</span> <span class="keyword">public</span> DecoratorStream&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">BufferedStream</span>(Stream* stm):<span class="built_in">DecoratorStream</span>(stm)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Process</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//运行时装配</span></span><br><span class="line">    FileStream* s1=<span class="keyword">new</span> <span class="built_in">FileStream</span>();</span><br><span class="line">    </span><br><span class="line">    CryptoStream* s2=<span class="keyword">new</span> <span class="built_in">CryptoStream</span>(s1);</span><br><span class="line">    </span><br><span class="line">    BufferedStream* s3=<span class="keyword">new</span> <span class="built_in">BufferedStream</span>(s1);</span><br><span class="line">    </span><br><span class="line">    BufferedStream* s4=<span class="keyword">new</span> <span class="built_in">BufferedStream</span>(s2);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>此时类关系：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214150930329.png" alt="image-20211214150930329"></p>
<p>类的规模：<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>1</mn><mo>+</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo>+</mo><mi>m</mi></mrow><annotation encoding="application/x-tex">1 + n + 1 + m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathdefault">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">m</span></span></span></span></p>
<h3 id="514-结构structure"><a class="markdownIt-Anchor" href="#514-结构structure"></a> 5.1.4 结构（Structure)</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214111213675.png" alt="image-20211214111213675"></p>
<p>【<em>注</em>：】</p>
<ul>
<li><code>Component</code> -&gt; <code>Stream</code>  (稳定)</li>
<li><code>Decorator</code> -&gt; <code>DecoratorStream</code> （稳定）</li>
<li><code>ConcreteComponent</code> -&gt; <code>FileStream</code>/<code>NetworkStream</code>/… （变化）</li>
<li><code>ConcreteDecoratorX</code>-&gt; <code>CryptoStream</code> / <code>BufferedStream</code> (变化)</li>
</ul>
<h3 id="515-要点总结"><a class="markdownIt-Anchor" href="#515-要点总结"></a> 5.1.5 要点总结</h3>
<ul>
<li>通过<strong>采用组合而非继承</strong>的手法，Decorator模式实现了在<mark>运行时</mark>动态扩展对象功能的能力，而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。</li>
<li>Decorator类在接口上表现为is-a Component的继承关系，即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系，即Decorator类又使用了另外一个Component类。【<em>注</em>：<code>DecoratorStream</code> 类继承自 <code>Stream</code>，同时又有一个<code>Stream</code>类型的字段，一般这种既继承又组合的方式通常都是装饰模式。例子中的继承是为了完善接口的规范，组合是为了支持实现具体的类】</li>
<li>Decorator模式的目的并非解决“多子类衍生的多继承”问题，Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。</li>
</ul>
<h2 id="52-bridge-桥模式"><a class="markdownIt-Anchor" href="#52-bridge-桥模式"></a> 5.2 Bridge 桥模式</h2>
<h3 id="521-动机motivation"><a class="markdownIt-Anchor" href="#521-动机motivation"></a> 5.2.1 动机（Motivation）</h3>
<ul>
<li>由于某些类型的固有的实现逻辑，使得它们具有两个变化的维度，乃至多个纬度的变化。</li>
<li>如何应对这种“多维度的变化”？如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化，而不引入额外的复杂度？</li>
</ul>
<h3 id="522-代码示例"><a class="markdownIt-Anchor" href="#522-代码示例"></a> 5.2.2 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//bridge1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Messager</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>=<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Messager</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//平台实现 n</span></span><br><span class="line"><span class="comment">//类的数目：1 + n + m * n</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PCMessagerBase</span> :</span> <span class="keyword">public</span> Messager&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MobileMessagerBase</span> :</span> <span class="keyword">public</span> Messager&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//业务抽象 </span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PCMessagerLite</span> :</span> <span class="keyword">public</span> PCMessagerBase &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        PCMessagerBase::<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        PCMessagerBase::<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        PCMessagerBase::<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PCMessagerPerfect</span> :</span> <span class="keyword">public</span> PCMessagerBase &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        PCMessagerBase::<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        PCMessagerBase::<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        PCMessagerBase::<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        PCMessagerBase::<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        PCMessagerBase::<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        PCMessagerBase::<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MobileMessagerLite</span> :</span> <span class="keyword">public</span> MobileMessagerBase &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        MobileMessagerBase::<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        MobileMessagerBase::<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        MobileMessagerBase::<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MobileMessagerPerfect</span> :</span> <span class="keyword">public</span> MobileMessagerBase &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        MobileMessagerBase::<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        MobileMessagerBase::<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        MobileMessagerBase::<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        MobileMessagerBase::<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        MobileMessagerBase::<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        MobileMessagerBase::<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Process</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//编译时装配</span></span><br><span class="line">    Messager *m = <span class="keyword">new</span> <span class="built_in">MobileMessagerPerfect</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>基于装饰模式的经验，将业务的继承修改为组合，进行如下的修改：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Messager</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//存在着多个变化的维度：平台实现 + 业务抽象</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>=<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Messager</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//平台实现 n</span></span><br><span class="line"><span class="comment">//类的数目：1 + n + m * n</span></span><br><span class="line"><span class="comment">//主要到这个类里只实现了Messager这个类的部分接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PCMessagerBase</span> :</span> <span class="keyword">public</span> Messager&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MobileMessagerBase</span> :</span> <span class="keyword">public</span> Messager&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//业务抽象 </span></span><br><span class="line"><span class="comment">//主要到这个类里只需要实现了Messager这个类的部分接口，如果继承Messager是不合适的</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MessagerLite</span> &#123;</span></span><br><span class="line">    Messager* messager; <span class="comment">//指针才具有多态性</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messager-&gt;<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messager-&gt;<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messager-&gt;<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MessagerPerfect</span> &#123;</span></span><br><span class="line">    Messager* messager;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        messager-&gt;<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        messager-&gt;<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messager-&gt;<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        messager-&gt;<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messager-&gt;<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        messager-&gt;<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Process</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//编译时装配</span></span><br><span class="line">    Messager *m = <span class="keyword">new</span> <span class="built_in">MobileMessagerPerfect</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>因为<code>PCMessageBase</code>类和<code>MessagerLite</code>、<code>MessagerPerfect</code>类都各自只实现了<code>Messager</code>的部分接口，说明<code>Messager</code>中的两部分的接口不应该放到一起，应该进行拆分：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//bridge2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Messager</span>&#123;</span></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">     MessagerImp* messagerImp;<span class="comment">//...</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Messager</span>(MessagerImpl* mimp) : <span class="built_in">messagerImpl</span>(mimp) &#123; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Messager</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MessagerImp</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">MessagerImp</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//平台实现 n</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PCMessagerImp</span> :</span> <span class="keyword">public</span> MessagerImp&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MobileMessagerImp</span> :</span> <span class="keyword">public</span> MessagerImp&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PlaySound</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">DrawShape</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">WriteText</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Connect</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//==========</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//业务抽象 m</span></span><br><span class="line"><span class="comment">//类的数目：1+n+m</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MessagerLite</span> :</span> <span class="keyword">public</span> Messager &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MessagerLite</span>(MessagerImp* mimp) : <span class="built_in">Messager</span>(mimp) &#123; </span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messagerImp-&gt;<span class="built_in">Connect</span>(); <span class="comment">//messagerImpl字段在父类中声明了</span></span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messagerImp-&gt;<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messagerImp-&gt;<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MessagerPerfect</span>  :</span><span class="keyword">public</span> Messager &#123;</span><br><span class="line"><span class="keyword">public</span>: </span><br><span class="line">    <span class="built_in">MessagerPerfect</span>(MessagerImp* mimp) : <span class="built_in">Messager</span>(mimp) &#123; </span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(string username, string password)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messagerImp-&gt;<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        messagerImp-&gt;<span class="built_in">Connect</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendMessage</span><span class="params">(string message)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messagerImp-&gt;<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        messagerImp-&gt;<span class="built_in">WriteText</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SendPicture</span><span class="params">(Image image)</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        messagerImp-&gt;<span class="built_in">PlaySound</span>();</span><br><span class="line">        <span class="comment">//********</span></span><br><span class="line">        messagerImp-&gt;<span class="built_in">DrawShape</span>();</span><br><span class="line">        <span class="comment">//........</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Process</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="comment">//运行时装配</span></span><br><span class="line">    MessagerImp* mImp = <span class="keyword">new</span> <span class="built_in">PCMessagerImp</span>();</span><br><span class="line">    Messager *m = <span class="keyword">new</span> <span class="built_in">Messager</span>(mImp);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="523-模式定义"><a class="markdownIt-Anchor" href="#523-模式定义"></a> 5.2.3 模式定义</h3>
<blockquote>
<p>将抽象部分(业务功能)与实现部分(平台实现)分离，使它们都可以独立地变化。——《设计模式》GoF</p>
</blockquote>
<h3 id="524-结构structure"><a class="markdownIt-Anchor" href="#524-结构structure"></a> 5.2.4 结构（Structure）</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214111534980.png" alt="image-20211214111534980"></p>
<ul>
<li>
<p><em><code>Abstraction</code></em> -&gt; <em><code>Messgaer</code></em> (稳定)  【<code>imp</code>对应到代码中就是 <code>Messager</code> 中有一个<code>MessagerImpl</code>类型的指针变量】</p>
</li>
<li>
<p><em><code>Implementor</code></em> -&gt; <em><code>MessagerImpl</code></em> （稳定）</p>
</li>
<li>
<p><code>RefinedAbstraction</code> -&gt; <code>MessagerLite</code>  / <code>MessagerPerfect</code> (变化)</p>
</li>
<li>
<p><code>ConcreteImplementorX</code> -&gt; <code>XXMessagerImpl</code> (变化)</p>
</li>
</ul>
<p>两个方向独立变化，而不是杂糅在一起。</p>
<h3 id="525-要点总结"><a class="markdownIt-Anchor" href="#525-要点总结"></a> 5.2.5 要点总结</h3>
<ul>
<li>Bridge模式使用“<strong>对象间的组合关系</strong>”解耦了抽象和实现之间固有的绑定关系，使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化，即“子类化”它们。</li>
<li>Bridge模式有时候类似于多继承方案，但是多继承方案往往违背单一职责原则（即一个类只有一个变化的原因），复用性比较差。Bridge模式是比多继承方案更好的解决方法。</li>
<li>Bridge模式的应用一般在“两个非常强的变化维度”，有时一个类也有多于两个的变化维度，这时可以使用Bridge的扩展模式。</li>
</ul>
<h1 id="6-对象创建模式"><a class="markdownIt-Anchor" href="#6-对象创建模式"></a> 6、&quot;对象创建&quot;模式</h1>
<ul>
<li>通过“对象创建”模式绕开<code>new</code>，来避免对象创建（<code>new</code>）过程中所导致的紧耦合（依赖具体类），从而支持对象创建的稳定。它是接口抽象之后的第一步工作。</li>
<li>典型模式
<ul>
<li>Factory Method</li>
<li>Abstract Factory</li>
<li>Prototype</li>
<li>Builder</li>
</ul>
</li>
</ul>
<h2 id="61-factory-method-工厂方法"><a class="markdownIt-Anchor" href="#61-factory-method-工厂方法"></a> 6.1 Factory Method 工厂方法</h2>
<h3 id="611-动机motivation"><a class="markdownIt-Anchor" href="#611-动机motivation"></a> 6.1.1 动机（Motivation）</h3>
<ul>
<li>在软件系统中，经常面临着创建对象的工作；由于需求的变化，需要创建的对象的具体类型经常变化。</li>
<li>如何应对这种变化？如何绕过常规的对象创建方法(new)，提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合？</li>
</ul>
<h3 id="612-代码示例"><a class="markdownIt-Anchor" href="#612-代码示例"></a> 6.1.2 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BinarySplitter</span> </span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line">	ProgressBar* progressBar;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line">		<span class="function">FileSplitter <span class="title">splitter</span><span class="params">(filePath, number, progressBar)</span></span>;</span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>未来可能的需求：文本分割，图片分割，那就要新增：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISplitter</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">ISplitter</span>() &#123; &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BinarySplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//新增</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TxtSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PictureSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VideoSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>面向接口编程最简单的表现就是变量是接口类型，</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line">        <span class="comment">//ISplitter* splitter 是抽象依赖</span></span><br><span class="line">        <span class="comment">//new BinarySplitter(filePath, number) 是细节依赖，编译时细节依赖， 违背了依赖倒置原则，如何解决呢？</span></span><br><span class="line">		ISplitter* splitter = <span class="keyword">new</span> <span class="built_in">BinarySplitter</span>(filePath, number); <span class="comment">//依赖具体类</span></span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>”对象创建“ 模式就是要绕开这个<code>new</code> 带来的问题，这是面向接口编程必然要面临的需求，上述代码中的第13行等号左右两边都变成依赖抽象。可以考虑通过一个方法返回对象。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//SplitterFactory1.cpp</span></span><br><span class="line"><span class="comment">//抽象类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISplitter</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">ISplitter</span>() &#123; &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//工厂基类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SplitterFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">BinaryFiltter</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line">        SplitterFactory factory;</span><br><span class="line">		ISplitter* splitter = factory.<span class="built_in">createSplitter</span>(); </span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>因为SplitterFactory编译时依赖了BinarySplitter，而MainForm编译时依赖了SplitterFactory，所以相当于MainForm编译时依赖了BinarySplitter，所以还是没有解决问题。那应该怎么办呢？</p>
<p><strong>虚函数是运行时依赖</strong>，所以修改<code>SplitterFactory.cpp</code>:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//SplitterFactory.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SplitterFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">SplitterFactory</span>() &#123; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISplitter</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">ISplitter</span>() &#123; &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm3.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	TextBox* txtFilePath;</span><br><span class="line">	TextBox* txtFileNumber;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		string filePath = txtFilePath-&gt;<span class="built_in">getText</span>();</span><br><span class="line">		<span class="keyword">int</span> number = <span class="built_in">atoi</span>(txtFileNumber-&gt;<span class="built_in">getText</span>().<span class="built_in">c_str</span>());</span><br><span class="line">        </span><br><span class="line">        SplitterFactory* factory;</span><br><span class="line">		ISplitter* splitter = factory-&gt;<span class="built_in">createSplitter</span>();  <span class="comment">//多态</span></span><br><span class="line">        </span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>未来的对象实际是什么类型依赖于<code>factory</code>，那么<code>factory</code>的实际类型是什么呢：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FileSplitter2.cpp</span></span><br><span class="line"><span class="comment">//具体类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BinarySplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TxtSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PictureSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VideoSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//具体工厂</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BinarySplitterFactory</span> :</span> <span class="keyword">public</span> SplitterFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">BinarySplitter</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TxtSplitterFactory</span> :</span> <span class="keyword">public</span> SplitterFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">TxtSplitter</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PictureSplitterFactory</span> :</span> <span class="keyword">public</span> SplitterFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">PictureSplitter</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VideoSplitterFactory</span> :</span> <span class="keyword">public</span> SplitterFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">VideoSplitter</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm3.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	SplitterFactory* factory; <span class="comment">//工厂</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MainForm</span>(SplitterFactory* factory) &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;factory = factory;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		ISplitter* splitter = factory-&gt;<span class="built_in">createSplitter</span>();  <span class="comment">//多态new</span></span><br><span class="line">		splitter.<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>可以发现，通过这种改善，<code>MainForm</code> 只依赖 <code>SplitterFactory</code> 和 <code>ISplitter</code> 这两个抽象，而没有依赖具体类。不是消灭变化，而是将变化赶到一个局部的地方。</p>
<h3 id="613-模式定义"><a class="markdownIt-Anchor" href="#613-模式定义"></a> 6.1.3 模式定义</h3>
<blockquote>
<p>定义一个用于创建对象的接口，让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟（目的：解耦，手段：虚函数）到子类。——《设计模式》GoF</p>
</blockquote>
<p>注：&quot;解耦&quot;是解new和后面具体的类的耦合。</p>
<h3 id="614-结构"><a class="markdownIt-Anchor" href="#614-结构"></a> 6.1.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214111825656.png" alt="image-20211214111825656"></p>
<p>注：</p>
<ul>
<li><code>Product</code> -&gt; <code>ISplitter</code> (稳定)</li>
<li><code>ConcreteProduct</code> -&gt; <code>XXSplitter</code> （稳定）</li>
<li><code>Creator</code> -&gt; <code>SplitterFactory</code> （变化）</li>
<li><code>ConcreteCreator</code> -&gt; <code>XXSplitterFactory</code> （变化）</li>
</ul>
<h3 id="615-要点总结"><a class="markdownIt-Anchor" href="#615-要点总结"></a> 6.1.5 要点总结</h3>
<ul>
<li>Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型，紧耦合关系(new)会导致软件的脆弱。</li>
<li>Factory Method模式通过<strong>面向对象</strong>【注：多态】的手法，将所要创建的具体对象工作<strong>延迟</strong>到子类，从而实现一种<strong>扩展</strong>（而非更改）的策略，较好地解决了这种紧耦合关系。【注：“延迟” 对应到代码中就是 <code>MainForm</code> 类中，一开始只要有需求变化，就要修改对应的代码，而改善后<code>MainForm</code>中不会因为需求的变化而进行更改，只需要加子类和子类的工厂即可，然后将具体的类传给<code>MainForm</code>。】</li>
<li>Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。</li>
</ul>
<h2 id="62-abstract-factory-抽象工厂"><a class="markdownIt-Anchor" href="#62-abstract-factory-抽象工厂"></a> 6.2 Abstract Factory 抽象工厂</h2>
<h3 id="621-动机motivation"><a class="markdownIt-Anchor" href="#621-动机motivation"></a> 6.2.1 动机（Motivation）</h3>
<ul>
<li>在软件系统中，经常面临着“一系列相互依赖的对象”的创建工作；同时，由于需求的变化，往往存在更多系列对象的创建工作。</li>
<li>如何应对这种变化？如何绕过常规的对象创建方法(new)，提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合？</li>
</ul>
<h3 id="622-代码示例"><a class="markdownIt-Anchor" href="#622-代码示例"></a> 6.2.2 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//EmployeeDAO1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeDAO</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">vector&lt;EmployeeDO&gt; <span class="title">GetEmployees</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        SqlConnection* connection = <span class="keyword">new</span> <span class="built_in">SqlConnection</span>();</span><br><span class="line">        connection-&gt;ConnectionString = <span class="string">&quot;...&quot;</span>;</span><br><span class="line">        </span><br><span class="line">        SqlCommand* command = <span class="keyword">new</span> <span class="built_in">SqlCommand</span>();</span><br><span class="line">        command-&gt;CommandText = <span class="string">&quot;...&quot;</span>;</span><br><span class="line">        command-&gt;<span class="built_in">SetConnection</span>(connection);</span><br><span class="line">        </span><br><span class="line">        SqlDataReader* reader = command-&gt;<span class="built_in">ExecuteReader</span>();</span><br><span class="line">        <span class="keyword">while</span> (reader-&gt;<span class="built_in">Read</span>()) &#123;</span><br><span class="line">            </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//缺点: 类与SqlServer绑定了</span></span><br></pre></td></tr></table></figure>
<p>修改为面向接口编程，如果使用工厂方法：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//EmployeeDAO2.cpp</span></span><br><span class="line"><span class="comment">//数据库访问有关的基类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBConnection</span> &#123;</span>&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBConnectionFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBConnection* <span class="title">createDBConnection</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBCommand</span> &#123;</span>&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBCommandFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBCommand* <span class="title">createDBCommand</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDataReader</span> &#123;</span>&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDataReaderFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDataReader* <span class="title">createDataReader</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//支持SQL Server</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlConnection</span>:</span> <span class="keyword">public</span> IDBConnection &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlConnectionFactory</span>:</span> <span class="keyword">public</span> IDBConnectionFactory &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlCommand</span>:</span> <span class="keyword">public</span> IDBCommand &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlCommandFactory</span>:</span> <span class="keyword">public</span> IDBCommandFactory &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlDataReader</span>:</span> <span class="keyword">public</span> IDataReader &#123;&#125;;    </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlDataReaderFactory</span>:</span> <span class="keyword">public</span> IDataReaderFactory &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//支持 Oracle</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleConnection</span>:</span> <span class="keyword">public</span> IDBConnection &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleConnectionFactory</span>:</span> <span class="keyword">public</span> IDBConnectionFactory &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleCommand</span>:</span> <span class="keyword">public</span> IDBCommand &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleCommandFactory</span>:</span> <span class="keyword">public</span> IDBCommandFactory &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleDataReader</span>:</span> <span class="keyword">public</span> IDataReader &#123;&#125;;   </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleDataReadeFactory</span>:</span> <span class="keyword">public</span> IDataReaderFactory &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeDAO</span> &#123;</span> </span><br><span class="line">    <span class="comment">//在构造器中初始化 这三个必须是一个系列的，如果是sql的就是sql系列的</span></span><br><span class="line">    IDBConnectionFactory* dbConnectionFactory;</span><br><span class="line">    IDBCommandFactory* dbCommandFactory;</span><br><span class="line">    IDataReaderFactory* dataReaderFactory;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">vector&lt;EmployeeDO&gt; <span class="title">GetEmployees</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        IDBConnection* connection = dbConnectionFactory-&gt;<span class="built_in">createDBConnection</span>();</span><br><span class="line">        connection-&gt;<span class="built_in">ConnectionString</span>(<span class="string">&quot;...&quot;</span>);</span><br><span class="line">        </span><br><span class="line">        IDBCommand* command = dbCommandFactory-&gt;<span class="built_in">createDBCommand</span>();</span><br><span class="line">        command-&gt;<span class="built_in">CommandText</span>(<span class="string">&quot;...&quot;</span>);</span><br><span class="line">        command-&gt;<span class="built_in">SetConnection</span>(connection); <span class="comment">//关联性</span></span><br><span class="line">        </span><br><span class="line">        IDataReader* reader = command-&gt;<span class="built_in">ExecuteReader</span>();</span><br><span class="line">        <span class="keyword">while</span> (reader-&gt;<span class="built_in">Read</span>()) &#123;</span><br><span class="line">            </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>三个工厂指针变量必须是一个系列的，因为 command 和 connection 是有关联性的。如果传了一个 Sql 的 connection，而传了一个 Oracle 的 Command 就乱套了。所以这时候，使用抽象工厂：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//EmployeeDAO3.cpp</span></span><br><span class="line"><span class="comment">//数据库访问有关的基类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBConnection</span> &#123;</span>&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBCommand</span> &#123;</span>&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDataReader</span> &#123;</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDBFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//因为三个有相关性，所以考虑把它们放到一个工厂里</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBConnection* <span class="title">createDBConnection</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBCommand* <span class="title">createDBCommand</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDataReader* <span class="title">createDataReader</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//支持SQL Server</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlConnection</span>:</span> <span class="keyword">public</span> IDBConnection &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlCommand</span>:</span> <span class="keyword">public</span> IDBCommand &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlDataReader</span>:</span> <span class="keyword">public</span> IDataReader &#123;&#125;;    </span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqlDBFactory</span>:</span> <span class="keyword">public</span> IDBFactory &#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBConnection* <span class="title">createDBConnection</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBCommand* <span class="title">createDBCommand</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDataReader* <span class="title">createDataReader</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//支持 Oracle</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleConnection</span>:</span> <span class="keyword">public</span> IDBConnection &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleCommand</span>:</span> <span class="keyword">public</span> IDBCommand &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleDataReader</span>:</span> <span class="keyword">public</span> IDataReader &#123;&#125;;   </span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OracleDBFactory</span>:</span> <span class="keyword">public</span> IDBFactory &#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBConnection* <span class="title">createDBConnection</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDBCommand* <span class="title">createDBCommand</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IDataReader* <span class="title">createDataReader</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeDAO</span> &#123;</span> </span><br><span class="line">    IDBFactory* dbFactory;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">vector&lt;EmployeeDO&gt; <span class="title">GetEmployees</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        IDBConnection* connection = dbFactory-&gt;<span class="built_in">createDBConnection</span>();</span><br><span class="line">        connection-&gt;<span class="built_in">ConnectionString</span>(<span class="string">&quot;...&quot;</span>);</span><br><span class="line">        </span><br><span class="line">        IDBCommand* command = dbFactory-&gt;<span class="built_in">createDBCommand</span>();</span><br><span class="line">        command-&gt;<span class="built_in">CommandText</span>(<span class="string">&quot;...&quot;</span>);</span><br><span class="line">        command-&gt;<span class="built_in">SetConnection</span>(connection); <span class="comment">//关联性</span></span><br><span class="line">        </span><br><span class="line">        IDataReader* reader = command-&gt;<span class="built_in">ExecuteReader</span>(); <span class="comment">//关联性</span></span><br><span class="line">        <span class="keyword">while</span> (reader-&gt;<span class="built_in">Read</span>()) &#123;</span><br><span class="line">            </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="623-模式定义"><a class="markdownIt-Anchor" href="#623-模式定义"></a> 6.2.3 模式定义</h3>
<blockquote>
<p>提供一个接口，让该接口负责创建一系列“相关或者相互依赖的对象”，无需指定它们具体的类。——《设计模式》GoF</p>
</blockquote>
<h3 id="624-结构"><a class="markdownIt-Anchor" href="#624-结构"></a> 6.2.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214112025783.png" alt="image-20211214112025783"></p>
<p>注：</p>
<ul>
<li><code>AbstractFactory</code> -&gt; <code>IDBFactory</code> (稳定)</li>
<li><code>AbstractProductA</code> -&gt; <code>IDBConnection</code> （稳定）</li>
<li><code>AbstractProductB</code> -&gt;  <code>IDBCommand</code> / <code>IDataReader</code> （稳定）</li>
<li><code>ConcreteFactoryX</code> -&gt; <code>SqlDBFactory</code> / <code>OracleDBFactory</code> (变化)</li>
</ul>
<h3 id="625-要点总结"><a class="markdownIt-Anchor" href="#625-要点总结"></a> 6.2.5 要点总结</h3>
<ul>
<li>如果没有应对“多系列对象构建”的需求变化，则没有必要使用Abstract Factory模式，这时候使用简单的工厂完全可以。</li>
<li>“系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。</li>
<li>Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。</li>
</ul>
<h2 id="63-prototype-原型模式"><a class="markdownIt-Anchor" href="#63-prototype-原型模式"></a> 6.3 Prototype 原型模式</h2>
<h3 id="631-动机motivation"><a class="markdownIt-Anchor" href="#631-动机motivation"></a> 6.3.1 动机（Motivation）</h3>
<ul>
<li>在软件系统中，经常面临着“某些结构复杂的对象”的创建工作；由于需求的变化，这些对象经常面临着剧烈的变化，但是它们却拥有比较稳定一致的接口。</li>
<li>如何应对这种变化？如何向“客户程序（使用这些对象的程序）” 隔离出 “这些易变对象” ，从而使得 “依赖这些易变对象的客户程序” 不随着需求改变而改变？</li>
</ul>
<h3 id="632-代码示例"><a class="markdownIt-Anchor" href="#632-代码示例"></a> 6.3.2 代码示例</h3>
<p>工厂方法中的<code>ISplitterFactory.cpp</code>：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//ISplitterFactory.cpp</span></span><br><span class="line"><span class="comment">//抽象类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISplitter</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">ISplitter</span>() &#123; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//工厂基类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SplitterFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ISplitter* <span class="title">createSplitter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">BinaryFiltter</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">SplitterFactory</span>() &#123;&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>原型模式将这两个类进行了合并：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//ISplitterFactory.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISplitter</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">split</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">clone</span><span class="params">()</span> </span>= <span class="number">0</span>; <span class="comment">//通过克隆自己来创建指针</span></span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">ISplitter</span>() &#123; &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FileSplitter.cpp</span></span><br><span class="line"><span class="comment">//具体类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BinarySplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">     <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">clone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">BinarySplitter</span>(*<span class="keyword">this</span>); <span class="comment">//克隆自己，通过拷贝构造</span></span><br><span class="line">     &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TxtSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">clone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">TxtSplitter</span>(*<span class="keyword">this</span>); <span class="comment">//克隆自己，通过拷贝构造</span></span><br><span class="line">     &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PictureSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">clone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">PictureSplitter</span>(*<span class="keyword">this</span>); <span class="comment">//克隆自己，通过拷贝构造</span></span><br><span class="line">     &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VideoSplitter</span> :</span> <span class="keyword">public</span> ISplitter</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> ISplitter* <span class="title">clone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">VideoSplitter</span>(*<span class="keyword">this</span>); <span class="comment">//克隆自己，通过拷贝构造进行深克隆</span></span><br><span class="line">     &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//MainForm.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainForm</span> :</span> <span class="keyword">public</span> Form</span><br><span class="line">&#123;</span><br><span class="line">	ISplitter* prototype; <span class="comment">//原型对象</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MainForm</span>(ISplitter* prototype) &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;prototype = prototype;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">	<span class="function"><span class="keyword">void</span> <span class="title">Button1_Click</span><span class="params">()</span></span>&#123;</span><br><span class="line">		ISplitter* splitter = prototype-&gt;<span class="built_in">clone</span>(); <span class="comment">//克隆原型</span></span><br><span class="line">		splitter-&gt;<span class="built_in">split</span>();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="633-模式定义"><a class="markdownIt-Anchor" href="#633-模式定义"></a> 6.3.3 模式定义</h3>
<blockquote>
<p>使用原型实例指定创建对象的种类，然后通过拷贝这些原型来创建新的对象。 ——《设计模式》 GoF</p>
</blockquote>
<h3 id="634-结构"><a class="markdownIt-Anchor" href="#634-结构"></a> 6.3.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211215175435380.png" alt="image-20211215175435380"></p>
<ul>
<li><code>Prototype</code> -&gt; <code>ISplitter</code></li>
<li><code>ConcretePrototypeX</code> -&gt; <code>XXSplitter</code></li>
<li><code>Client</code> -&gt; <code>MainForm</code></li>
</ul>
<h3 id="635-要点总结"><a class="markdownIt-Anchor" href="#635-要点总结"></a> 6.3.5 要点总结</h3>
<ul>
<li>Prototype模式同样用于隔离类对象的使用者和具体类型（易变类）之间的耦合关系，它同样要求这些“易变类”拥有“稳定的接口”。</li>
<li>Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做，它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象（即原型），然后在任何需要的地方Clone。</li>
<li>Prototype模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。</li>
</ul>
<h2 id="64-builder-构建器"><a class="markdownIt-Anchor" href="#64-builder-构建器"></a> 6.4 Builder 构建器</h2>
<h3 id="641-动机-motivation"><a class="markdownIt-Anchor" href="#641-动机-motivation"></a> 6.4.1 动机 (Motivation)</h3>
<ul>
<li>在软件系统中，有时候面临着“一个复杂对象”的创建工作，其通常由各个部分的子对象用一定的算法构成；由于需求的变化，这个复杂对象的各个部分经常面临着剧烈的变化，但是将它们组合在一起的算法却相对稳定。</li>
<li>如何应对这种变化？如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化，从而保持系统中的“稳定构建算法”不随着需求改变而改变？</li>
</ul>
<h3 id="642-模式定义"><a class="markdownIt-Anchor" href="#642-模式定义"></a> 6.4.2 模式定义</h3>
<blockquote>
<p>将一个复杂对象的构建与其表示相分离，使得同样的构建过程(稳定)可以创建不同的表示(变化)。——《设计模式》GoF</p>
</blockquote>
<h3 id="643-代码示例"><a class="markdownIt-Anchor" href="#643-代码示例"></a> 6.4.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//builder.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">House</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuilderPart1</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">bool</span> flag = <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart3</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (flag) &#123; <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart4</span>(); &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart5</span>();</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>说明：构造房子的流程不变，但是每个子步骤是变化的。此处不能将构造的流程直接放到构造函数里面：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//builder.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">House</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">   <span class="comment">//这种方式不可！！！不能放在构造函数里面</span></span><br><span class="line">   <span class="built_in">House</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuilderPart1</span>(); <span class="comment">//静态绑定</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">bool</span> flag = <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart3</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (flag) &#123; <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart4</span>(); &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart5</span>();</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>因为C++中在构造函数里不可以调用子类的虚函数，因为是静态绑定。原因是子类的构造函数是先调用父类的构造函数，如果在父类的构造函数里调用子类的虚函数的override版本，就会导致子类的构造函数还没完成，但是子类的虚函数被调用了。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//builder.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">House</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuilderPart1</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">bool</span> flag = <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart3</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (flag) &#123; <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart4</span>(); &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart5</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">House</span>() &#123; &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StoneHouse</span> :</span> <span class="keyword">public</span> House &#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    House* pHouse = <span class="keyword">new</span> <span class="built_in">StoneHouse</span>()；</span><br><span class="line">    pHouse-&gt;<span class="built_in">Init</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>一个类中的东西太多不太好，就要进行分离，需要将<code>House</code>构建过程进行提取单独封装为一个类：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">House</span> &#123;</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HouseBuilder</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuilderPart1</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">bool</span> flag = <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart3</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (flag) &#123; <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart4</span>(); &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>-&gt;<span class="built_in">BuildPart5</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function">House* <span class="title">GetResult</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> pHouse;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">HouseBuilder</span>() &#123; &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    House* pHouse;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StoneHouse</span> :</span> <span class="keyword">public</span> House &#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//pHouse-&gt;Part1 = ...;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    House* pHouse = <span class="keyword">new</span> <span class="built_in">StoneHouse</span>()；</span><br><span class="line">    pHouse-&gt;<span class="built_in">Init</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>再将构建流程进行拆分：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//对象的表示</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">House</span> &#123;</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//对象的构建</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HouseBuilder</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">House* <span class="title">GetResult</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> pHouse;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">HouseBuilder</span>() &#123; &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    House* pHouse;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StoneHouse</span> :</span> <span class="keyword">public</span> House &#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//pHouse-&gt;Part1 = ...;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart2</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart3</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart4</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuildPart5</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StoneHouseBuilder</span> :</span> <span class="keyword">public</span> HouseBuilder &#123;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HouseDirector</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    HouseBuilder* pHouseBuilder;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">HouseDirector</span>(HouseBuilder* pHouseBuilder) &#123;</span><br><span class="line">    	<span class="keyword">this</span>-&gt;pHouseBuilder = pHouseBuilder;    </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function">House* <span class="title">Construct</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        pHouseBuilder-&gt;<span class="built_in">BuilderPart1</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            pHouseBuilder-&gt;<span class="built_in">BuildPart2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">bool</span> flag = pHouseBuilder-&gt;<span class="built_in">BuildPart3</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (flag) &#123; pHouseBuilder-&gt;<span class="built_in">BuildPart4</span>(); &#125;</span><br><span class="line">        </span><br><span class="line">        pHouseBuilder-&gt;<span class="built_in">BuildPart5</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> pHouseBuilder-&gt;<span class="built_in">GetResult</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="644-结构"><a class="markdownIt-Anchor" href="#644-结构"></a> 6.4.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214112347840.png" alt="image-20211214112347840"></p>
<ul>
<li><code>Director</code> -&gt; <code>HouseDirector</code> (稳定)</li>
<li><code>Builder</code> -&gt; <code>HouseBuilder</code> (稳定)</li>
<li><code>ConcreteBuilder</code> -&gt; <code>StoneHouseBuilder</code> （变化）</li>
</ul>
<h3 id="645-要点总结"><a class="markdownIt-Anchor" href="#645-要点总结"></a> 6.4.5 要点总结</h3>
<ul>
<li>Builder 模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的算法，而复杂对象的各个部分则经常变化。</li>
<li>变化点在哪里，封装哪里—— Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。</li>
<li>在Builder模式中，要注意不同语言中构造器内调用虚函数的差别（C++ vs. C#) 。</li>
</ul>
<h1 id="7-对象性能模式"><a class="markdownIt-Anchor" href="#7-对象性能模式"></a> 7、“对象性能”模式</h1>
<ul>
<li>面向对象很好地解决了“抽象”的问题，但是必不可免地要付出一定的代价。对于通常情况来讲，面向对象的成本大都可以忽略不计。但是某些情况，面向对象所带来的成本必须谨慎处理。</li>
<li>典型模式
<ul>
<li>Singleton</li>
<li>Flyweight</li>
</ul>
</li>
</ul>
<h2 id="71-singleton-单例模式"><a class="markdownIt-Anchor" href="#71-singleton-单例模式"></a> 7.1 Singleton 单例模式</h2>
<h3 id="711-动机motivation"><a class="markdownIt-Anchor" href="#711-动机motivation"></a> 7.1.1 动机（Motivation）</h3>
<ul>
<li>在软件系统中，经常有这样一些特殊的类，必须保证它们在系统中只存在一个实例，才能确保它们的逻辑正确性、以及良好的效率。</li>
<li>如何绕过常规的构造器，提供一种机制来保证一个类只有一个实例？</li>
<li>这应该是类设计者的责任，而不是使用者的责任。</li>
</ul>
<h3 id="712-代码示例"><a class="markdownIt-Anchor" href="#712-代码示例"></a> 7.1.2 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Singleton.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Singleton</span> &#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">  	<span class="comment">//必须将类的构造函数设为私有</span></span><br><span class="line">  	<span class="built_in">Singleton</span>();</span><br><span class="line">  	<span class="built_in">Singleton</span>(<span class="keyword">const</span> Singleton&amp; other);</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">static</span> Singleton* <span class="title">getInstance</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="keyword">static</span> Singleton* m_instance;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Singleton* Singleton::m_instance = <span class="literal">nullptr</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//线程非安全版本</span></span><br><span class="line"><span class="function">Singleton* <span class="title">Singleton::getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (m_instance == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">        m_instance = <span class="keyword">new</span> <span class="built_in">Singleton</span>()；</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> m_instance;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//线程安全版本，但锁的代价太高：m_instance不为空的时候，对于都是读操作的时候加锁是浪费</span></span><br><span class="line"><span class="function">Singleton* <span class="title">Singleton::getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Lock lock; <span class="comment">//函数结束的时候释放锁</span></span><br><span class="line">    <span class="keyword">if</span> (m_instace == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">        m_instance = <span class="keyword">new</span> <span class="built_in">Singleton</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> m_instance;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//双检查锁，但由于内存读写reorder不安全</span></span><br><span class="line"><span class="comment">//所有的编译器都可能会出现reorder</span></span><br><span class="line"><span class="function">Singleton* <span class="title">Singleton::getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (m_instance == <span class="literal">nullptr</span>) &#123; <span class="comment">//减小了m_instance不为空时都是读取操作时候的加锁代价</span></span><br><span class="line">        Lock lock;</span><br><span class="line">        <span class="keyword">if</span> (m_instance == <span class="literal">nullptr</span>) &#123; <span class="comment">//避免两个线程同时在m_instance为空时进来</span></span><br><span class="line">            <span class="comment">//常见顺序：1. 分配内存 2.调用构造器 3.内存地址返回</span></span><br><span class="line">            <span class="comment">//如果编译器reorder：1.分配内存 2.返回内存地址给m_instance 3.调用构造器。</span></span><br><span class="line">            <span class="comment">//如果threadA在还没有调用构造器的时候，threadB进来了，发现m_instance不为空，直接返回对象，此时的m_instance是不可用的，只是分配了一个原生内存，并没有执行构造器，对象的状态不对。double-check lock欺骗了threadB，threadB拿到的指针所指向的对象只有对象地址，而没有执行构造器，这就是双检查锁可能出现的问题。</span></span><br><span class="line">            m_instance = <span class="keyword">new</span> <span class="built_in">Singleton</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> m_instance;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//C++ 11版本之后的跨平台实现 (volatile)</span></span><br><span class="line">std::atomic&lt;Singleton*&gt; Singleton::m_instance;</span><br><span class="line">std::mutex Singleton::m_mutex;</span><br><span class="line"></span><br><span class="line"><span class="function">Singleton* <span class="title">Singleton::getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Singleton* tmp = m_instance.<span class="built_in">load</span>(std::memory_order_relaxed);</span><br><span class="line">    std::<span class="built_in">atomic_thread_fence</span>(std::memory_order_acquire);<span class="comment">//获取内存fence</span></span><br><span class="line">    <span class="keyword">if</span> (tmp == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">        <span class="function">std::lock_guard&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(m_mutex)</span></span>;</span><br><span class="line">        tmp = m_instance.<span class="built_in">load</span>(std::memory_order_relaxed);</span><br><span class="line">        <span class="keyword">if</span> (tmp == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">            tmp = <span class="keyword">new</span> Singleton; <span class="comment">//保证了tmp不会出现reorder</span></span><br><span class="line">            std::<span class="built_in">atomic_thread_fence</span>(std::memory_order_release);<span class="comment">//释放内存fence</span></span><br><span class="line">            m_instance.<span class="built_in">store</span>(tmp, std::memory_order_relaxed);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> tmp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="713-模式定义"><a class="markdownIt-Anchor" href="#713-模式定义"></a> 7.1.3 模式定义</h3>
<blockquote>
<p>保证一个类仅有一个实例，并提供一个该实例的全局访问点。					——《设计模式》GoF</p>
</blockquote>
<h3 id="714-结构"><a class="markdownIt-Anchor" href="#714-结构"></a> 7.1.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214113257215.png" alt="image-20211214113257215"></p>
<h3 id="715-要点总结"><a class="markdownIt-Anchor" href="#715-要点总结"></a> 7.1.5 要点总结</h3>
<ul>
<li>Singleton模式中的实例构造器可以设置为protected以允许子类派生。</li>
<li>Singleton模式一般不要支持拷贝构造函数和Clone接口，因为这有可能导致多个对象实例，与Singleton模式的初衷违背。</li>
<li>如何实现多线程环境下安全的Singleton？注意对双检查锁的正确实现。</li>
</ul>
<h2 id="72-flyweight-享元模式"><a class="markdownIt-Anchor" href="#72-flyweight-享元模式"></a> 7.2 Flyweight 享元模式</h2>
<h3 id="721-动机motivation"><a class="markdownIt-Anchor" href="#721-动机motivation"></a> 7.2.1 动机（Motivation）</h3>
<ul>
<li>在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中，从而带来很高的运行时代价——主要指内存需求方面的代价。</li>
<li>如何在避免大量细粒度对象问题的同时，让外部客户程序依然能够透明地使用面向对象的方式来进行操作？</li>
</ul>
<h3 id="722-代码示例"><a class="markdownIt-Anchor" href="#722-代码示例"></a> 7.2.2 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//flyweight.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Font</span> &#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="comment">//unique object key</span></span><br><span class="line">    string key;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//object state</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Font</span>(<span class="keyword">const</span> string&amp; key) &#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FontFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    map&lt;string, Font*&gt; fontPool;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">Font* <span class="title">GetFont</span><span class="params">(<span class="keyword">const</span> string&amp; key)</span> </span>&#123;</span><br><span class="line">        map&lt;string, Font*&gt;::iterator item = fontPool.<span class="built_in">find</span>(key);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (item != fontPool.<span class="built_in">end</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> fontPool[key];</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            Font* font = <span class="keyword">new</span> <span class="built_in">Font</span>(key);</span><br><span class="line">            fontPool[key] = font;</span><br><span class="line">            <span class="keyword">return</span> font;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>共享的方式：有就使用，没有就添加。</p>
<h3 id="723-模式定义"><a class="markdownIt-Anchor" href="#723-模式定义"></a> 7.2.3 模式定义</h3>
<blockquote>
<p>运用<strong>共享</strong>技术有效地支持大量细粒度的对象。														——《设计模式》GoF</p>
</blockquote>
<h3 id="724-结构"><a class="markdownIt-Anchor" href="#724-结构"></a> 7.2.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214114417809.png" alt="image-20211214114417809"></p>
<h3 id="715-要点总结-2"><a class="markdownIt-Anchor" href="#715-要点总结-2"></a> 7.1.5 要点总结</h3>
<ul>
<li>面向对象很好地解决了抽象性的问题，但是作为一个运行在机器中的程序实体，我们需要考虑对象的代价问题。Flyweight主要解决面向对象的代价问题，一般不触及面向对象的抽象性问题。</li>
<li>Flyweight采用对象共享的做法来降低系统中对象的个数，从而降低细粒度对象给系统带来的内存压力。在具体实现方面，要注意对象状态的处理。</li>
<li>对象的数量太大从而导致对象内存开销加大——什么样的数量才算大？这需要我们仔细地根据具体应用情况进行评估，而不能凭空臆断。</li>
</ul>
<h1 id="8-接口隔离模式"><a class="markdownIt-Anchor" href="#8-接口隔离模式"></a> 8、“接口隔离”模式</h1>
<ul>
<li>在组件构建过程中，某些接口之间直接的依赖常常会带来很多问题、甚至根本无法实现。采用添加一层<strong>间接</strong>（稳定）接口，来隔离本来互相紧密关联的接口是一种常见的解决方案。</li>
<li>典型模式
<ul>
<li>Facade 【注：解决系统内和系统外】</li>
<li>Proxy   【注：两个对象，由于安全/分布式/性能的原因不能直接依赖，必须隔离】</li>
<li>Adapter  【注：解决老接口和新接口的不匹配问题】</li>
<li>Mediator   【注：解耦系统内对象间的关联关系】</li>
</ul>
</li>
</ul>
<h2 id="81-facede-门面模式"><a class="markdownIt-Anchor" href="#81-facede-门面模式"></a> 8.1 Facede 门面模式</h2>
<h3 id="811-系统间耦合的复杂度"><a class="markdownIt-Anchor" href="#811-系统间耦合的复杂度"></a> 8.1.1 系统间耦合的复杂度</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214114916095.png" alt="image-20211214114916095"></p>
<h3 id="812-动机motivation"><a class="markdownIt-Anchor" href="#812-动机motivation"></a> 8.1.2 动机（Motivation)</h3>
<ul>
<li>上述 A 方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合，随着外部客户程序和各子系统的演化，这种过多的耦合面临很多变化的挑战。</li>
<li>如何简化外部客户系统和系统间的交互接口？如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦？</li>
</ul>
<h3 id="813-模式定义"><a class="markdownIt-Anchor" href="#813-模式定义"></a> 8.1.3 模式定义</h3>
<blockquote>
<p>为子系统中的一组接口提供一个一致（稳定）的界面，Facade 模式定义了一个高层接口，这个接口使得这一子系统更加容易使用（复用）。——《设计模式》 GoF</p>
</blockquote>
<h3 id="814-结构"><a class="markdownIt-Anchor" href="#814-结构"></a> 8.1.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216155412868.png" alt="image-20211216155412868"></p>
<p>注：</p>
<ul>
<li><code>Facade</code> （稳定）</li>
<li>其他的可能会变化</li>
</ul>
<h3 id="815-要点总结"><a class="markdownIt-Anchor" href="#815-要点总结"></a> 8.1.5 要点总结</h3>
<ul>
<li>从客户程序的角度来看，Facade模式简化了整个组件系统的接口，对于组件内部与外部客户程序来说，达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。</li>
<li>Facade设计模式更注重从<strong>架构</strong>的层次去看整个系统，而不是单个类的层次。Facade很多时候更是一种架构设计模式。</li>
<li>Facade设计模式并非一个集装箱，可以任意地放进任何多个对象。Facade模式中组件的内部应该是“相互耦合关系比较大的一系列组件”，而不是一个简单的功能集合。</li>
</ul>
<h2 id="82-proxy-代理模式"><a class="markdownIt-Anchor" href="#82-proxy-代理模式"></a> 8.2 Proxy 代理模式</h2>
<h3 id="821-动机motivation"><a class="markdownIt-Anchor" href="#821-动机motivation"></a> 8.2.1 动机（Motivation）</h3>
<ul>
<li>在面向对象系统中，有些对象由于某种原因（比如对象创建的开销很大，或者某些操作需要安全控制，或者需要进程外的访问等），直接访问会给使用者、或者系统结构带来很多麻烦。</li>
<li>如何在不失去<strong>透明操作</strong>（一致性）对象的同时来管理/控制这些对象特有的复杂性？增加一层间接层是软件开发中常见的解决方式。</li>
</ul>
<h3 id="822-模式定义"><a class="markdownIt-Anchor" href="#822-模式定义"></a> 8.2.2 模式定义</h3>
<blockquote>
<p>为其他对象提供一种代理以控制（隔离，使用接口）对这个对象的访问。											——《设计模式》GoF</p>
</blockquote>
<h3 id="823-结构"><a class="markdownIt-Anchor" href="#823-结构"></a> 8.2.3 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214142853300.png" alt="image-20211214142853300"></p>
<h3 id="824-代码示例"><a class="markdownIt-Anchor" href="#824-代码示例"></a> 8.2.4 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//client.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISubject</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RealSubject</span>:</span> <span class="keyword">public</span> ISubject&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//....</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ClientApp</span>&#123;</span></span><br><span class="line">    </span><br><span class="line">    ISubject* subject;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">ClientApp</span>()&#123;</span><br><span class="line">        subject=<span class="keyword">new</span> <span class="built_in">RealSubject</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">DoTask</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        subject-&gt;<span class="built_in">process</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//....</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//proxy.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ISubject</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//Proxy的设计</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubjectProxy</span>:</span> <span class="keyword">public</span> ISubject&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//对RealSubject的一种间接访问</span></span><br><span class="line">        <span class="comment">//....</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ClientApp</span>&#123;</span></span><br><span class="line">    </span><br><span class="line">    ISubject* subject;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">ClientApp</span>()&#123;</span><br><span class="line">        subject = <span class="keyword">new</span> <span class="built_in">SubjectProxy</span>(); <span class="comment">//可以通过某种工厂模式进行创建</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">DoTask</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        subject-&gt;<span class="built_in">process</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//....</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="825-要点总结"><a class="markdownIt-Anchor" href="#825-要点总结"></a> 8.2.5 要点总结</h3>
<ul>
<li>“增加一层间接层” 是软件系统中对许多复杂问题的一种常见解决方法。在面向对象系统中，直接使用某些对象会带来很多问题，作为间接层的proxy对象便是解决这一问题的常用手段。</li>
<li>具体proxy设计模式的实现方法、实现粒度都相差很大，有些可能对单个对象做细粒度的控制，如copy-on-write技术，有些可能对组件模块提供抽象代理层，在架构层次对对象做proxy。</li>
<li>Proxy 并不一定要求保持接口完整的一致性，只要能够实现间接控制，有时候损及一些透明性是可以接受的。</li>
</ul>
<h2 id="83-adapter-适配器模式"><a class="markdownIt-Anchor" href="#83-adapter-适配器模式"></a> 8.3 Adapter 适配器模式</h2>
<h3 id="831-动机"><a class="markdownIt-Anchor" href="#831-动机"></a> 8.3.1 动机</h3>
<ul>
<li>在软件系统中，由于应用环境的变化，常常需要将“一些现存的对象” 放在新的环境中应用，但是新环境要求的接口时这些现存对象所不满足的。</li>
<li>如何应对这种“迁移的变化”？如何既能利用现有对象的良好实现，同时又能满足新的应用环境所要求的接口？</li>
</ul>
<h3 id="832-我们身边的adapter"><a class="markdownIt-Anchor" href="#832-我们身边的adapter"></a> 8.3.2 我们身边的Adapter</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214143334978.png" alt="image-20211214143334978"></p>
<h3 id="833-模式定义"><a class="markdownIt-Anchor" href="#833-模式定义"></a> 8.3.3 模式定义</h3>
<blockquote>
<p>将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。  ——《设计模式》GoF</p>
</blockquote>
<h3 id="834-结构"><a class="markdownIt-Anchor" href="#834-结构"></a> 8.3.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214143441838.png" alt="image-20211214143441838"></p>
<ul>
<li><code>Target</code> 是希望的接口 （稳定）</li>
<li><code>Adaptee</code> 是以前的接口 （稳定）</li>
<li><code>Adapter</code> 具有和父类一样的接口规范，实现了<code>Adapter</code>向<code>Target</code>的转换 （变化）</li>
</ul>
<h3 id="835-代码示例"><a class="markdownIt-Anchor" href="#835-代码示例"></a> 8.3.5 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Adapter.cpp</span></span><br><span class="line"><span class="comment">//目标接口（新接口）</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ITarget</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//遗留接口（老接口）</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IAdaptee</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">foo</span><span class="params">(<span class="keyword">int</span> data)</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">bar</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//遗留类型</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OldClass</span>:</span> <span class="keyword">public</span> IAdaptee&#123;</span><br><span class="line">    <span class="comment">//....</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//GoF中适配器有两种：对象适配器和类适配器</span></span><br><span class="line"><span class="comment">//对象适配器：组合了一个对象</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Adapter</span>:</span> <span class="keyword">public</span> ITarget&#123; <span class="comment">//继承</span></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    IAdaptee* pAdaptee;<span class="comment">//组合</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Adapter</span>(IAdaptee* pAdaptee)&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;pAdaptee = pAdaptee;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> data = pAdaptee-&gt;<span class="built_in">bar</span>();</span><br><span class="line">        pAdaptee-&gt;<span class="built_in">foo</span>(data);</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//类适配器</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Adapter</span>:</span> <span class="keyword">public</span> ITarget, <span class="keyword">protected</span> OldClass&#123; <span class="comment">//多继承</span></span><br><span class="line">                           </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">    IAdaptee* pAdaptee = <span class="keyword">new</span> <span class="built_in">OldClass</span>();</span><br><span class="line"></span><br><span class="line">    ITarget* pTarget=<span class="keyword">new</span> <span class="built_in">Adapter</span>(pAdaptee);</span><br><span class="line">    pTarget-&gt;<span class="built_in">process</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//STL中的Adapter模式的应用:将dequeue转换成stack/queue</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">stack</span>&#123;</span></span><br><span class="line">    deqeue container;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">queue</span>&#123;</span></span><br><span class="line">    deqeue container;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="836-要点总结"><a class="markdownIt-Anchor" href="#836-要点总结"></a> 8.3.6 要点总结</h3>
<ul>
<li>Adapter模式主要应用于“希望复用一些现存的类，但是接口又与复用环境要求不一致的情况”，在遗留代码复用、类库迁移等方面非常有用。</li>
<li>GoF 23 定义了两种 Adapter 模式的实现结构：对象适配器和类适配器。但类适配器采用“多继承”的实现方式，一般不推荐使用。对象适配器采用“对象组合”的方式，更符合松耦合精神。</li>
<li>Adapter模式可以实现得非常灵活，不必拘泥于 GoF 23 中定义的两种结构。例如，完全可以将Adapter模式中的“现存现象”作为新的接口方法参数，来达到适配的目的。</li>
</ul>
<h2 id="84-mediator-中介者模式"><a class="markdownIt-Anchor" href="#84-mediator-中介者模式"></a> 8.4 Mediator 中介者模式</h2>
<h3 id="841-动机"><a class="markdownIt-Anchor" href="#841-动机"></a> 8.4.1 动机</h3>
<ul>
<li>在软件构建过程中，经常会出现多个对象互相关联交互的情况，对象之间常常会维持一种复杂的引用关系，如果遇到一些需求的更改，这种直接的引用关系将面临不断的变化。</li>
<li>在这种情况下，我们可使用一个“中介对象”来管理对象间的关联关系，避免相互交互的对象之间的紧耦合引用关系，从而更好地抵御变化。</li>
</ul>
<h3 id="842-模式定义"><a class="markdownIt-Anchor" href="#842-模式定义"></a> 8.4.2 模式定义</h3>
<blockquote>
<p>用一个中介对象来封装（封装变化）一系列的对象交互。中介者使各对象不需要显式地相互引用（编译时依赖-&gt;运行时依赖），从而使其耦合松散（管理变化），而且可以独立地改变它们之间的交互。																				——《设计模式》GoF</p>
</blockquote>
<h3 id="843-结构"><a class="markdownIt-Anchor" href="#843-结构"></a> 8.4.3 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211214144111911.png" alt="image-20211214144111911"></p>
<ul>
<li><code>Mediator</code> 和 <code>Colleague</code> 之间是双向依赖，而<code>ConcreteColleague</code> 之间没有依赖关系，通过这种方式达到了依赖的解耦</li>
</ul>
<p>梳理结构中的关系：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216182623494.png" alt="image-20211216182623494"></p>
<p>需要定义消息通知的规范/协议，比如1要和3通信，如何通过Mediator找到3，这就要通过消息通知的规范。</p>
<p>上图是将直接依赖关系 转化为 间接依赖关系，和Facade模式异曲同工，但是Facade解决的是系统内和系统外的耦合，而中介者模式解决的系统内各个组件之间的耦合。</p>
<h3 id="844-要点总结"><a class="markdownIt-Anchor" href="#844-要点总结"></a> 8.4.4 要点总结</h3>
<ul>
<li>将多个对象间复杂的关联关系解耦，Mediator模式将多个对象间的控制逻辑进行集中管理【注：定义一套调用机制的协议】，变“多个对象互相关联”为“多个对象和一个中介者关联”，简化了系统的维护，抵御了可能的变化。</li>
<li>随着控制逻辑的复杂化，Mediator具体对象的实现可能相当复杂。这时候可以对Mediator对象进行分解处理。</li>
<li>Facade模式是解耦系统间（单向）的对象关联关系；Mediator模式是解耦系统内各个对象之间（双向）的关联关系。</li>
</ul>
<h1 id="9-状态变化模式"><a class="markdownIt-Anchor" href="#9-状态变化模式"></a> 9、“状态变化”模式</h1>
<ul>
<li>在组件构建过程中，某些对象的状态经常面临变化，如何对这些变化进行有效的管理？同时又维持高层模块的稳定？“状态变化”模式为这一问题提供了一种解决方案。</li>
<li>典型模式
<ul>
<li>State</li>
<li>Memento</li>
</ul>
</li>
</ul>
<h2 id="91-state状态模式"><a class="markdownIt-Anchor" href="#91-state状态模式"></a> 9.1 State状态模式</h2>
<h3 id="911-动机motivation"><a class="markdownIt-Anchor" href="#911-动机motivation"></a> 9.1.1 动机（Motivation）</h3>
<ul>
<li>在软件构建过程中，某些对象的状态如果改变，其行为也会随之而发生变化，比如文档处于只读状态，其支持的行为和读写状态支持的行为就可能完全不同。</li>
<li>如何在运行时根据对象的状态来透明地更改对象的行为？而不会为对象操作和状态转化之间引入紧耦合？</li>
</ul>
<h3 id="912-代码示例"><a class="markdownIt-Anchor" href="#912-代码示例"></a> 9.1.2 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//state1.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">NetworkState</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    Network_Open,</span><br><span class="line">    Network_Close,</span><br><span class="line">    Network_Connect,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NetworkProcessor</span>&#123;</span></span><br><span class="line">    </span><br><span class="line">    NetworkState state;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation1</span><span class="params">()</span></span>&#123; <span class="comment">//根据state不同而操作不同</span></span><br><span class="line">        <span class="keyword">if</span> (state == Network_Open)&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//**********</span></span><br><span class="line">            state = Network_Close;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (state == Network_Close)&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//..........</span></span><br><span class="line">            state = Network_Connect;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (state == Network_Connect)&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//$$$$$$$$$$</span></span><br><span class="line">            state = Network_Open;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Operation2</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (state == Network_Open)&#123;</span><br><span class="line">            </span><br><span class="line">            <span class="comment">//**********</span></span><br><span class="line">            state = Network_Connect;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (state == Network_Close)&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//.....</span></span><br><span class="line">            state = Network_Open;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (state == Network_Connect)&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//$$$$$$$$$$</span></span><br><span class="line">            state = Network_Close;</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Operation3</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>枚举类型中如何添加了一种的状态，那么操作里面都要进行改变，违反了开闭原则。</p>
<p>将枚举类型转换为抽象基类，操作变成状态对象的行为：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//state2.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NetworkState</span>&#123;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    NetworkState* pNext;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation1</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation2</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation3</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">NetworkState</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OpenState</span> :</span><span class="keyword">public</span> NetworkState&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">static</span> NetworkState* m_instance;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">static</span> NetworkState* <span class="title">getInstance</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (m_instance == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">            m_instance = <span class="keyword">new</span> <span class="built_in">OpenState</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> m_instance;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//**********</span></span><br><span class="line">        pNext = CloseState::<span class="built_in">getInstance</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation2</span><span class="params">()</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//..........</span></span><br><span class="line">        pNext = ConnectState::<span class="built_in">getInstance</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation3</span><span class="params">()</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//$$$$$$$$$$</span></span><br><span class="line">        pNext = OpenState::<span class="built_in">getInstance</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CloseState</span>:</span><span class="keyword">public</span> NetworkState&#123; &#125;;</span><br><span class="line"><span class="comment">//...</span></span><br><span class="line"><span class="comment">//扩展</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WaitState</span>:</span> <span class="keyword">public</span> NetworkState &#123; &#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NetworkProcessor</span>&#123;</span></span><br><span class="line">    </span><br><span class="line">    NetworkState* pState;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">NetworkProcessor</span>(NetworkState* pState)&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>-&gt;pState = pState;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        pState-&gt;<span class="built_in">Operation1</span>();</span><br><span class="line">        pState = pState-&gt;pNext;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation2</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        pState-&gt;<span class="built_in">Operation2</span>();</span><br><span class="line">        pState = pState-&gt;pNext;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation3</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        pState-&gt;<span class="built_in">Operation3</span>();</span><br><span class="line">        pState = pState-&gt;pNext;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>当状态增加的时候，<code>NetworkProcesser</code>中不必发生改变，达到了稳定。</p>
<h3 id="913-模式定义"><a class="markdownIt-Anchor" href="#913-模式定义"></a> 9.1.3 模式定义</h3>
<blockquote>
<p>允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。 ——《设计模式》GoF</p>
</blockquote>
<h3 id="914-结构"><a class="markdownIt-Anchor" href="#914-结构"></a> 9.1.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216184709433.png" alt="image-20211216184709433"></p>
<ul>
<li><code>Context</code> -&gt; <code>NetworkProcesser</code> （稳定）</li>
<li><code>State</code> -&gt; <code>NetworkState</code> (稳定)</li>
<li><code>ConcreteStateX</code> -&gt; <code>xxState</code> （变化）</li>
</ul>
<h3 id="915-要点总结"><a class="markdownIt-Anchor" href="#915-要点总结"></a> 9.1.5 要点总结</h3>
<ul>
<li>State模式将所有与一个特定状态相关的行为都放入一个 State 的子类对象中，在对象状态切换时，切换相应的对象；但同时维持 State 的接口，这样实现了具体操作与状态转换之间的解耦。</li>
<li>为不同的状态引入不同的对象使得状态转换变得更加明确，而且可以保证不会出现状态不一致的情况，因为转换是原子性的——即要么彻底转换过来，要么不转换。</li>
<li>如果State对象没有实例变量，那么各个上下文可以共享同一个 State 对象【注：使用了Singleton模式】，从而节省对象开销。</li>
</ul>
<h2 id="92-memento-备忘录"><a class="markdownIt-Anchor" href="#92-memento-备忘录"></a> 9.2 Memento 备忘录</h2>
<h3 id="921-动机motivation"><a class="markdownIt-Anchor" href="#921-动机motivation"></a> 9.2.1 动机（Motivation）</h3>
<ul>
<li>在软件构建过程中，某些对象的状态在转换过程中，可能由于某种需要，要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态，便会暴露对象的细节实现。</li>
<li>如何实现对象状态的良好保存与恢复？但同时又不会因此而破坏对象本身的封装性。</li>
</ul>
<h3 id="922-模式定义"><a class="markdownIt-Anchor" href="#922-模式定义"></a> 9.2.2 模式定义</h3>
<blockquote>
<p>在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。																									——《设计模式》GoF</p>
</blockquote>
<h3 id="923-代码示例"><a class="markdownIt-Anchor" href="#923-代码示例"></a> 9.2.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//memento.cpp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Memento</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    string state;</span><br><span class="line">    <span class="comment">//..</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Memento</span>(<span class="keyword">const</span> string &amp; s) : <span class="built_in">state</span>(s) &#123;&#125;</span><br><span class="line">    <span class="function">string <span class="title">getState</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> state; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setState</span><span class="params">(<span class="keyword">const</span> string &amp; s)</span> </span>&#123; state = s; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Originator</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    string state;</span><br><span class="line">    <span class="comment">//....</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Originator</span>() &#123;&#125;</span><br><span class="line">    <span class="function">Memento <span class="title">createMomento</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="function">Memento <span class="title">m</span><span class="params">(state)</span></span>;</span><br><span class="line">        <span class="keyword">return</span> m;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setMomento</span><span class="params">(<span class="keyword">const</span> Memento &amp; m)</span> </span>&#123;</span><br><span class="line">        state = m.<span class="built_in">getState</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Originator orginator;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//捕获对象状态，存储到备忘录</span></span><br><span class="line">    Memento mem = orginator.<span class="built_in">createMomento</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//... 改变orginator状态</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//从备忘录中恢复</span></span><br><span class="line">    orginator.<span class="built_in">setMomento</span>(memento);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="924-结构"><a class="markdownIt-Anchor" href="#924-结构"></a> 9.2.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216185906831.png" alt="image-20211216185906831"></p>
<h3 id="925-要点总结"><a class="markdownIt-Anchor" href="#925-要点总结"></a> 9.2.5 要点总结</h3>
<ul>
<li>备忘录（Memento）存储原发器（Originator）对象的内部状态，在需要时恢复原发器状态。</li>
<li>Memento模式的核心是信息隐藏，即Originator需要向外界隐藏信息，保持其封装性。但同时又需要将状态保存到外界（Memento）。</li>
<li>由于现代语言运行时（如C#、Java等）都具有相当的对象序列化支持，因此往往采用效率较高、又较容易正确实现的序列化方案来实现Memento模式。</li>
</ul>
<h1 id="10-数据结构模式"><a class="markdownIt-Anchor" href="#10-数据结构模式"></a> 10、“数据结构”模式</h1>
<ul>
<li>常常有一些组件在内部具有特定的数据结构，如果让客户程序依赖这些特定的数据结构，将极大地破坏组件的复用。这时候，将这些特定数据结构封装在内部，在外部提供统一的接口，来实现与特定数据结构无关的访问，是一种行之有效的解决方案。</li>
<li>典型模式
<ul>
<li>Composite 【注：树形结构】</li>
<li>Iterator    【注：遍历需求】</li>
<li>Chain of Responsibility  【注：单链表】</li>
</ul>
</li>
</ul>
<h2 id="101-composite模式"><a class="markdownIt-Anchor" href="#101-composite模式"></a> 10.1 Composite模式</h2>
<h3 id="1011-动机"><a class="markdownIt-Anchor" href="#1011-动机"></a> 10.1.1 动机</h3>
<ul>
<li>软件在某些情况下，客户代码过多地依赖于对象容器复杂的内部实现结构，对象容器内部实现结构（而非抽象接口）的变化将引起客户代码的频繁变化，带来了代码的维护性、扩展性等弊端。</li>
<li>如何将“客户代码与复杂的对象容器结构”解耦？让对象容器自己来实现自身的复杂结构，从而使得客户代码就像处理简单对象一样来处理复杂的对象容器？</li>
</ul>
<h3 id="1012-模式定义"><a class="markdownIt-Anchor" href="#1012-模式定义"></a> 10.1.2 模式定义</h3>
<blockquote>
<p>将对象组合成<mark>树形结构</mark>以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性（稳定）。 ——《设计模式》GoF</p>
</blockquote>
<h3 id="1013-代码示例"><a class="markdownIt-Anchor" href="#1013-代码示例"></a> 10.1.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//composite.cpp</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;list&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;algorithm&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Component</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Component</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//树节点</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Composite</span> :</span> <span class="keyword">public</span> Component&#123;</span><br><span class="line">    </span><br><span class="line">    string name;</span><br><span class="line">    list&lt;Component*&gt; elements;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Composite</span>(<span class="keyword">const</span> string &amp; s) : <span class="built_in">name</span>(s) &#123;&#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(Component* element)</span> </span>&#123;</span><br><span class="line">        elements.<span class="built_in">push_back</span>(element);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">remove</span><span class="params">(Component* element)</span></span>&#123;</span><br><span class="line">        elements.<span class="built_in">remove</span>(element);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//1. process current node</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">//2. process leaf nodes</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> &amp;e : elements)</span><br><span class="line">            e-&gt;<span class="built_in">process</span>(); <span class="comment">//多态调用</span></span><br><span class="line">         </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//叶子节点</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Leaf</span> :</span> <span class="keyword">public</span> Component&#123;</span><br><span class="line">    string name;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Leaf</span>(string s) : <span class="built_in">name</span>(s) &#123;&#125;</span><br><span class="line">            </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//process current node</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Invoke</span><span class="params">(Component &amp; c)</span></span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    c.<span class="built_in">process</span>();</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Composite <span class="title">root</span><span class="params">(<span class="string">&quot;root&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">Composite <span class="title">treeNode1</span><span class="params">(<span class="string">&quot;treeNode1&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">Composite <span class="title">treeNode2</span><span class="params">(<span class="string">&quot;treeNode2&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">Composite <span class="title">treeNode3</span><span class="params">(<span class="string">&quot;treeNode3&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">Composite <span class="title">treeNode4</span><span class="params">(<span class="string">&quot;treeNode4&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">Leaf <span class="title">leaf1</span><span class="params">(<span class="string">&quot;leaf1&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">Leaf <span class="title">leaf2</span><span class="params">(<span class="string">&quot;leaf2&quot;</span>)</span></span>;</span><br><span class="line">    </span><br><span class="line">    root.<span class="built_in">add</span>(&amp;treeNode1);</span><br><span class="line">    treeNode1.<span class="built_in">add</span>(&amp;treeNode2);</span><br><span class="line">    treeNode2.<span class="built_in">add</span>(&amp;leaf1);</span><br><span class="line">    </span><br><span class="line">    root.<span class="built_in">add</span>(&amp;treeNode3);</span><br><span class="line">    treeNode3.<span class="built_in">add</span>(&amp;treeNode4);</span><br><span class="line">    treeNode4.<span class="built_in">add</span>(&amp;leaf2);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//对单个对象和组合对象的一致性</span></span><br><span class="line">    <span class="built_in">process</span>(root);</span><br><span class="line">    <span class="built_in">process</span>(leaf2);</span><br><span class="line">    <span class="built_in">process</span>(treeNode3);</span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1013-结构"><a class="markdownIt-Anchor" href="#1013-结构"></a> 10.1.3 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211216192351521.png" alt="image-20211216192351521"></p>
<h3 id="1014-要点总结"><a class="markdownIt-Anchor" href="#1014-要点总结"></a> 10.1.4 要点总结</h3>
<ul>
<li>Composite模式采用树形结构来实现普遍存在的对象容器，从而将“一对多”的关系转化为“一对一”的关系，使得客户代码可以一致地（复用）处理对象和对象容器，无需关心处理的是单个的对象，还是组合的对象容器。</li>
<li>将“客户代码与复杂的对象容器结构”解耦是 Composite 的核心思想，解耦之后，客户代码将与纯粹的抽象接口——而非对象容器的内部实现结构——发生依赖，从而更能“应对变化”。</li>
<li>Composite模式在具体实现中，可以让父对象中的子对象反向追溯；如果父对象有频繁的遍历需求，可使用缓存技巧来改善效率。</li>
</ul>
<h2 id="102-iterator迭代器"><a class="markdownIt-Anchor" href="#102-iterator迭代器"></a> 10.2 Iterator迭代器</h2>
<h3 id="1021-动机motivation"><a class="markdownIt-Anchor" href="#1021-动机motivation"></a> 10.2.1 动机（Motivation)</h3>
<ul>
<li>在软件构建过程中，集合对象内部结构常常变化各异。但对于这些集合对象，我们希望在不暴露其内部结构的同时，可以让外部客户代码透明地访问其中包含的元素；同时这种&quot;透明遍历&quot; 也为 “同一种算法在多种集合对象上进行操作”提供了可能。【注：通过迭代器隔离算法和容器】</li>
<li>使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了而一种优雅的方式。</li>
</ul>
<h3 id="1022-模式定义"><a class="markdownIt-Anchor" href="#1022-模式定义"></a> 10.2.2 模式定义</h3>
<blockquote>
<p>提供一种方法顺序访问一个聚合对象中的各个元素，而又不暴露（稳定）该对象的内部表示。——《设计模式》GoF</p>
</blockquote>
<h3 id="1023-代码示例"><a class="markdownIt-Anchor" href="#1023-代码示例"></a> 10.2.3 代码示例</h3>
<p>GoF中使用面向对象的方法实现迭代器，这种方法在C<ins>语言中已经过时，因为这种模式里的虚函数调用是有成本的，间接调用，运行时多态；而C</ins>中的泛型编程使用的是基于模板的多态性，是编译时多态，性能高于基于虚函数面向对象的方式的迭代器。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Iterator.cpp</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Iterator</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">first</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">next</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">isDone</span><span class="params">()</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> T&amp; <span class="title">current</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyCollection</span>&#123;</span> <span class="comment">//Aggregate</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function">Iterator&lt;T&gt; <span class="title">GetIterator</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CollectionIterator</span> :</span> <span class="keyword">public</span> Iterator&lt;T&gt;&#123;</span><br><span class="line">    MyCollection&lt;T&gt; mc;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">CollectionIterator</span>(<span class="keyword">const</span> MyCollection&lt;T&gt; &amp; c): <span class="built_in">mc</span>(c)&#123; &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">first</span><span class="params">()</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">next</span><span class="params">()</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isDone</span><span class="params">()</span> <span class="keyword">const</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function">T&amp; <span class="title">current</span><span class="params">()</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MyAlgorithm</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyCollection&lt;<span class="keyword">int</span>&gt; mc;</span><br><span class="line">    </span><br><span class="line">    Iterator&lt;<span class="keyword">int</span>&gt; iter= mc.<span class="built_in">GetIterator</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">for</span> (iter.<span class="built_in">first</span>(); !iter.<span class="built_in">isDone</span>(); iter.<span class="built_in">next</span>())&#123;</span><br><span class="line">        cout &lt;&lt; iter.<span class="built_in">current</span>() &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1024-结构"><a class="markdownIt-Anchor" href="#1024-结构"></a> 10.2.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211218122357202.png" alt="image-20211218122357202"></p>
<h3 id="1024-要点总结"><a class="markdownIt-Anchor" href="#1024-要点总结"></a> 10.2.4 要点总结</h3>
<ul>
<li>迭代抽象：访问一个聚合对象的内容而无需暴露它的内部表示。</li>
<li>迭代多态：为遍历不同的集合结构提供一个统一的接口，从而支持同样的算法在不同的集合结构上进行操作。</li>
<li>迭代器的健壮性考虑：遍历的同时更改迭代器所在的集合结构，会导致问题。</li>
</ul>
<h2 id="103-chain-of-responsibility职责链"><a class="markdownIt-Anchor" href="#103-chain-of-responsibility职责链"></a> 10.3  Chain of Responsibility职责链</h2>
<h3 id="1031-动机"><a class="markdownIt-Anchor" href="#1031-动机"></a> 10.3.1 动机</h3>
<ul>
<li>在软件构建过程中，一个请求可能被多个对象处理，但是每个请求在运行时只能有一个接受者，如果显式指定，将必不可少地带来请求发送者与接受者的紧耦合。</li>
<li>如何使请求的发送者不需要指定具体的接受者？让请求的接受者自己在运行时决定来处理请求，从而使两者解耦。</li>
</ul>
<h3 id="1032-模式定义"><a class="markdownIt-Anchor" href="#1032-模式定义"></a> 10.3.2 模式定义</h3>
<blockquote>
<p>使多个对象都有机会处理请求，从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链【注：单向链表】，并沿着这条链传递请求，直到有一个对象处理它为止。  ——《设计模式》GoF</p>
</blockquote>
<h3 id="1033-代码示例"><a class="markdownIt-Anchor" href="#1033-代码示例"></a> 10.3.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//ChainofResponsibility.cpp</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="keyword">class</span> <span class="title">RequestType</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    REQ_HANDLER1,</span><br><span class="line">    REQ_HANDLER2,</span><br><span class="line">    REQ_HANDLER3</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Reqest</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    string description;</span><br><span class="line">    RequestType reqType;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Reqest</span>(<span class="keyword">const</span> string &amp; desc, RequestType type) : <span class="built_in">description</span>(desc), <span class="built_in">reqType</span>(type) &#123;&#125;</span><br><span class="line">    <span class="function">RequestType <span class="title">getReqType</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> reqType; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">const</span> string&amp; <span class="title">getDescription</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> description; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ChainHandler</span>&#123;</span></span><br><span class="line">    </span><br><span class="line">    ChainHandler *nextChain; <span class="comment">//形成多态链表</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">sendReqestToNextHandler</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (nextChain != <span class="literal">nullptr</span>)</span><br><span class="line">            nextChain-&gt;<span class="built_in">handle</span>(req);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">canHandleRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">processRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> </span>= <span class="number">0</span>;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">ChainHandler</span>() &#123; nextChain = <span class="literal">nullptr</span>; &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setNextChain</span><span class="params">(ChainHandler *next)</span> </span>&#123; nextChain = next; &#125;</span><br><span class="line">   </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">handle</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">canHandleRequest</span>(req))</span><br><span class="line">            <span class="built_in">processRequest</span>(req);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            <span class="built_in">sendReqestToNextHandler</span>(req);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handler1</span> :</span> <span class="keyword">public</span> ChainHandler&#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">canHandleRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> req.<span class="built_in">getReqType</span>() == RequestType::REQ_HANDLER1;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">processRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Handler1 is handle reqest: &quot;</span> &lt;&lt; req.<span class="built_in">getDescription</span>() &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">        </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handler2</span> :</span> <span class="keyword">public</span> ChainHandler&#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">canHandleRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> req.<span class="built_in">getReqType</span>() == RequestType::REQ_HANDLER2;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">processRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Handler2 is handle reqest: &quot;</span> &lt;&lt; req.<span class="built_in">getDescription</span>() &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handler3</span> :</span> <span class="keyword">public</span> ChainHandler&#123;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">canHandleRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> req.<span class="built_in">getReqType</span>() == RequestType::REQ_HANDLER3;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">processRequest</span><span class="params">(<span class="keyword">const</span> Reqest &amp; req)</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Handler3 is handle reqest: &quot;</span> &lt;&lt; req.<span class="built_in">getDescription</span>() &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Handler1 h1;</span><br><span class="line">    Handler2 h2;</span><br><span class="line">    Handler3 h3;</span><br><span class="line">    h1.<span class="built_in">setNextChain</span>(&amp;h2);</span><br><span class="line">    h2.<span class="built_in">setNextChain</span>(&amp;h3);</span><br><span class="line">    </span><br><span class="line">    <span class="function">Reqest <span class="title">req</span><span class="params">(<span class="string">&quot;process task ... &quot;</span>, RequestType::REQ_HANDLER3)</span></span>;</span><br><span class="line">    h1.<span class="built_in">handle</span>(req);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1034-结构"><a class="markdownIt-Anchor" href="#1034-结构"></a> 10.3.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211218122448277.png" alt="image-20211218122448277"></p>
<ul>
<li><code>Client</code> 和 <code>Handler</code> 稳定的</li>
<li><code>ConcreteHandlerX</code> 是变化的</li>
</ul>
<h3 id="1034-要点总结"><a class="markdownIt-Anchor" href="#1034-要点总结"></a> 10.3.4 要点总结</h3>
<ul>
<li>Chain of Responsibility 模式的应用场合在于“一个请求可能有多个接受者，但是最后真正的接受者只有一个”，这时候请求发送者与接受者的耦合有可能出现“变化脆弱”的症状，职责链的目的就是将二者解耦，从而更好地应对变化。</li>
<li>应用了Chain of Responsibility 模式后，对象的职责分配将更具灵活性。我们可以在<mark>运行时动态</mark>添加/修改请求的处理职责。</li>
<li>如果请求传递到职责链的末尾仍得不到处理，应该有一个合理的缺省机制。这也是每一个接受对象的责任，而不是发出请求的对象的责任。</li>
</ul>
<h1 id="11-行为变化模式"><a class="markdownIt-Anchor" href="#11-行为变化模式"></a> 11、“行为变化”模式</h1>
<ul>
<li>在组件的构建过程中，组件行为的变化经常导致组件本身剧烈的变化。“行为变化”模式将组件的行为和组件本身进行解耦，从而支持组件行为的变化，实现两者之间的松耦合。</li>
<li>典型模式
<ul>
<li>Command</li>
<li>Visitor</li>
</ul>
</li>
</ul>
<h2 id="111-command-命令模式"><a class="markdownIt-Anchor" href="#111-command-命令模式"></a> 11.1 Command 命令模式</h2>
<h3 id="1111-动机"><a class="markdownIt-Anchor" href="#1111-动机"></a> 11.1.1 动机</h3>
<ul>
<li>在软件构建过程中，“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比如需要对行为进行“记录、撤销/重（undo/redo)、事务”等处理，这种无法抵御变化的紧耦合是不合适的。</li>
<li>在这种情况下，如何将“行为请求者”与“行为实现者”解耦？将一组行为抽象为对象，可以实现二者之间的松耦合。</li>
</ul>
<h3 id="1112-模式定义"><a class="markdownIt-Anchor" href="#1112-模式定义"></a> 11.1.2 模式定义</h3>
<blockquote>
<p>将一个请求（行为）封装为一个对象，从而使你可用不同的请求对客户进行参数化；对请求排队或记录请求日志，以及支持可撤销的操作。——《设计模式》GoF</p>
</blockquote>
<h3 id="1113-代码示例"><a class="markdownIt-Anchor" href="#1113-代码示例"></a> 11.1.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Command.cpp</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Command</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteCommand1</span> :</span> <span class="keyword">public</span> Command</span><br><span class="line">&#123;</span><br><span class="line">    string arg;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">ConcreteCommand1</span>(<span class="keyword">const</span> string &amp; a) : <span class="built_in">arg</span>(a) &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">execute</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout&lt;&lt; <span class="string">&quot;#1 process...&quot;</span>&lt;&lt;arg&lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteCommand2</span> :</span> <span class="keyword">public</span> Command</span><br><span class="line">&#123;</span><br><span class="line">    string arg;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">ConcreteCommand2</span>(<span class="keyword">const</span> string &amp; a) : <span class="built_in">arg</span>(a) &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">execute</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout&lt;&lt; <span class="string">&quot;#2 process...&quot;</span>&lt;&lt;arg&lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MacroCommand</span> :</span> <span class="keyword">public</span> Command</span><br><span class="line">&#123;</span><br><span class="line">    vector&lt;Command*&gt; commands;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">addCommand</span><span class="params">(Command *c)</span> </span>&#123; commands.<span class="built_in">push_back</span>(c); &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">execute</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> &amp;c : commands)</span><br><span class="line">        &#123;</span><br><span class="line">            c-&gt;<span class="built_in">execute</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function">ConcreteCommand1 <span class="title">command1</span><span class="params">(receiver, <span class="string">&quot;Arg ###&quot;</span>)</span></span>;</span><br><span class="line">    <span class="function">ConcreteCommand2 <span class="title">command2</span><span class="params">(receiver, <span class="string">&quot;Arg $$$&quot;</span>)</span></span>;</span><br><span class="line">    </span><br><span class="line">    MacroCommand macro;</span><br><span class="line">    macro.<span class="built_in">addCommand</span>(&amp;command1);</span><br><span class="line">    macro.<span class="built_in">addCommand</span>(&amp;command2);</span><br><span class="line">    </span><br><span class="line">    macro.<span class="built_in">execute</span>();</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1114-结构"><a class="markdownIt-Anchor" href="#1114-结构"></a> 11.1.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219114054727.png" alt="image-20211219114054727"></p>
<ul>
<li><code>Command</code> 稳定</li>
<li><code>ConcreteCommand</code> 变化</li>
</ul>
<h3 id="1115-要点总结"><a class="markdownIt-Anchor" href="#1115-要点总结"></a> 11.1.5 要点总结</h3>
<ul>
<li>Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦，在面向对象语言中，常见的实现手段是“将行为抽象为对象”。</li>
<li>实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能会保存一些额外的状态信息。通过使用Composite模式，可以将多个“命令”封装为一个“复合命令”MacroCommand。</li>
<li>Command模式与C<ins>中的函数对象有些类似。但两者定义行为接口的规范有所区别：Command以面向对象中的“接口-实现”来定义行为接口规范，更严格，但有性能损失；C</ins>函数对象以函数签名来定义行为接口规范，更灵活，性能更高。</li>
</ul>
<h2 id="112-visitor访问器"><a class="markdownIt-Anchor" href="#112-visitor访问器"></a> 11.2 Visitor访问器</h2>
<h3 id="1121-动机"><a class="markdownIt-Anchor" href="#1121-动机"></a> 11.2.1 动机</h3>
<ul>
<li>在软件构建过程中，由于需求的改变，某些类层次结构【注：从基类到子类】中常常需要增加新的行为（方法），如果直接在基类中做这样的更改，将会给子类带来很繁重的变更负担，甚至破坏原有设计。</li>
<li>如何在不更改类层次结构的前提下，在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作，从而避免上述问题？</li>
</ul>
<h3 id="1122-模式定义"><a class="markdownIt-Anchor" href="#1122-模式定义"></a> 11.2.2 模式定义</h3>
<blockquote>
<p>表示一个作用于某对象结构中的各元素的操作。使得可以在不改变（稳定）各元素的类的前提下定义（扩展）作用于这些元素的新操作（变化）。  ——《设计模式》GoF</p>
</blockquote>
<h3 id="1123-代码示例"><a class="markdownIt-Anchor" href="#1123-代码示例"></a> 11.2.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//visitor1.cpp</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Visitor</span>;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Element</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Func1</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Func2</span><span class="params">(<span class="keyword">int</span> data)</span></span>=<span class="number">0</span>; <span class="comment">//若有新需求时，更改基类，则子类也会随着改变，负担很重</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Func3</span><span class="params">(<span class="keyword">int</span> data)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Element</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ElementA</span> :</span> <span class="keyword">public</span> Element</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Func1</span><span class="params">()</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Func2</span><span class="params">(<span class="keyword">int</span> data)</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ElementB</span> :</span> <span class="keyword">public</span> Element</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Func1</span><span class="params">()</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        <span class="comment">//***</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Func2</span><span class="params">(<span class="keyword">int</span> data)</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        <span class="comment">//***</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>使用Visitor模式：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//visitor2.cpp</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Visitor</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Element</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">accept</span><span class="params">(Visitor&amp; visitor)</span> </span>= <span class="number">0</span>; <span class="comment">//第一次多态辨析</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Element</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ElementA</span> :</span> <span class="keyword">public</span> Element</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">accept</span><span class="params">(Visitor &amp;visitor)</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        visitor.<span class="built_in">visitElementA</span>(*<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ElementB</span> :</span> <span class="keyword">public</span> Element</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">accept</span><span class="params">(Visitor &amp;visitor)</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        visitor.<span class="built_in">visitElementB</span>(*<span class="keyword">this</span>); <span class="comment">//第二次多态辨析</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Visitor</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">visitElementA</span><span class="params">(ElementA&amp; element)</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">visitElementB</span><span class="params">(ElementB&amp; element)</span> </span>= <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Visitor</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//上面是已经设计好的，不更改</span></span><br><span class="line"><span class="comment">//==================================</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//扩展1</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Visitor1</span> :</span> <span class="keyword">public</span> Visitor&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">visitElementA</span><span class="params">(ElementA&amp; element)</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Visitor1 is processing ElementA&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">        </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">visitElementB</span><span class="params">(ElementB&amp; element)</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Visitor1 is processing ElementB&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">     </span><br><span class="line"><span class="comment">//扩展2</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Visitor2</span> :</span> <span class="keyword">public</span> Visitor&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">visitElementA</span><span class="params">(ElementA&amp; element)</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Visitor2 is processing ElementA&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">visitElementB</span><span class="params">(ElementB&amp; element)</span> <span class="keyword">override</span></span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Visitor2 is processing ElementB&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Visitor2 visitor;</span><br><span class="line">    ElementB elementB;</span><br><span class="line">    elementB.<span class="built_in">accept</span>(visitor);<span class="comment">// double dispatch</span></span><br><span class="line">    </span><br><span class="line">    ElementA elementA;</span><br><span class="line">    elementA.<span class="built_in">accept</span>(visitor);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="1124-结构"><a class="markdownIt-Anchor" href="#1124-结构"></a> 11.2.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219115720763.png" alt="image-20211219115720763"></p>
<ul>
<li><code>Visitor</code>、<code>Element</code>、<code>ConcreteElementA</code>和 <code>ConcreteElementB</code> 必须是稳定的，使用<code>Visitor</code>模式的前提是必须知道<code>Element</code>有几个子类，对应的设计几个访问函数，<code>Vistor</code>稳定的前提是<code>Element</code>的所有子类都确定，这是这个模式非常大的缺点；如果<code>Element</code>类层次结构无法稳定，则<code>Visitor</code>模式不适用了；</li>
<li><code>ConcreteVisito1</code> 和 <code>ConcreteVisitor2</code> 是可以变化的。</li>
</ul>
<h3 id="1125-要点总结"><a class="markdownIt-Anchor" href="#1125-要点总结"></a> 11.2.5 要点总结</h3>
<ul>
<li>Visitor模式通过所谓<mark>双重分发</mark>（double dispatch）来是按在不更改（不添加新的操作-编译时）Element类层次结构的前提下，在运行时透明地为类层次结构上的各个类动态添加新的操作（支持变化）。</li>
<li>所谓双重分发即Visitor模式中间包括了两个多态分发（注意其中的多态机制）：第一个为accept方法的多态辨析；第二个为VisitElementX方法的多态辨析。</li>
<li>Visitor模式的最大缺点在于扩展类层次结构（增添新的Element子类），会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定，而其中的操作却经常面临频繁改动”。</li>
</ul>
<h1 id="12-领域规则模式"><a class="markdownIt-Anchor" href="#12-领域规则模式"></a> 12、“领域规则”模式</h1>
<ul>
<li>在特定领域中，某些变化虽然频繁，但可以抽象为某种规则。这时候，结合特定领域，将问题抽象为语法规则，从而给出在该领域下的一般性解决方案。</li>
<li>典型模式
<ul>
<li>Interpreter</li>
</ul>
</li>
</ul>
<h2 id="121-interpreter解析器"><a class="markdownIt-Anchor" href="#121-interpreter解析器"></a> 12.1 Interpreter解析器</h2>
<h3 id="1211-动机"><a class="markdownIt-Anchor" href="#1211-动机"></a> 12.1.1 动机</h3>
<ul>
<li>在软件构建过程中，如果某一特定领域的问题比较复杂，类似的结构不断重复出现，如果使用普通的编程方式来实现将面临非常频繁的变化。</li>
<li>在这种情况下，将特定领域的问题表达为某种语法规则下的橘子，然后构建一个解释器来解释这样的句子，从而达到解决问题的目的。</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219124009451.png" alt="image-20211219124009451"></p>
<h3 id="1212-模式定义"><a class="markdownIt-Anchor" href="#1212-模式定义"></a> 12.1.2 模式定义</h3>
<blockquote>
<p>给定一个语言，定义它的文法的一种表示，并定义一种解释器，这个解释器使用该表示来解释语言中的句子。   ——《设计模式》GoF</p>
</blockquote>
<h3 id="1213-代码示例"><a class="markdownIt-Anchor" href="#1213-代码示例"></a> 12.1.3 代码示例</h3>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;map&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stack&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Expression</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">interpreter</span><span class="params">(map&lt;<span class="keyword">char</span>, <span class="keyword">int</span>&gt; var)</span></span>=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Expression</span>()&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//变量表达式</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VarExpression</span>:</span> <span class="keyword">public</span> Expression &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">char</span> key;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">VarExpression</span>(<span class="keyword">const</span> <span class="keyword">char</span>&amp; key)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;key = key;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">interpreter</span><span class="params">(map&lt;<span class="keyword">char</span>, <span class="keyword">int</span>&gt; var)</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> var[key];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//符号表达式</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SymbolExpression</span> :</span> <span class="keyword">public</span> Expression &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 运算符左右两个参数</span></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    Expression* left;</span><br><span class="line">    Expression* right;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">SymbolExpression</span>( Expression* left,  Expression* right):</span><br><span class="line">        <span class="built_in">left</span>(left),<span class="built_in">right</span>(right)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//加法运算</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AddExpression</span> :</span> <span class="keyword">public</span> SymbolExpression &#123;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">AddExpression</span>(Expression* left, Expression* right):</span><br><span class="line">        <span class="built_in">SymbolExpression</span>(left,right)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">interpreter</span><span class="params">(map&lt;<span class="keyword">char</span>, <span class="keyword">int</span>&gt; var)</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> left-&gt;<span class="built_in">interpreter</span>(var) + right-&gt;<span class="built_in">interpreter</span>(var);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//减法运算</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubExpression</span> :</span> <span class="keyword">public</span> SymbolExpression &#123;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">SubExpression</span>(Expression* left, Expression* right):</span><br><span class="line">        <span class="built_in">SymbolExpression</span>(left,right)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">interpreter</span><span class="params">(map&lt;<span class="keyword">char</span>, <span class="keyword">int</span>&gt; var)</span> <span class="keyword">override</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> left-&gt;<span class="built_in">interpreter</span>(var) - right-&gt;<span class="built_in">interpreter</span>(var);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function">Expression*  <span class="title">analyse</span><span class="params">(string expStr)</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    stack&lt;Expression*&gt; expStack;</span><br><span class="line">    Expression* left = <span class="literal">nullptr</span>;</span><br><span class="line">    Expression* right = <span class="literal">nullptr</span>;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;expStr.<span class="built_in">size</span>(); i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in"><span class="keyword">switch</span></span>(expStr[i])</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;+&#x27;</span>:</span><br><span class="line">                <span class="comment">// 加法运算</span></span><br><span class="line">                left = expStack.<span class="built_in">top</span>();</span><br><span class="line">                right = <span class="keyword">new</span> <span class="built_in">VarExpression</span>(expStr[++i]);</span><br><span class="line">                expStack.<span class="built_in">push</span>(<span class="keyword">new</span> <span class="built_in">AddExpression</span>(left, right));</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;-&#x27;</span>:</span><br><span class="line">                <span class="comment">// 减法运算</span></span><br><span class="line">                left = expStack.<span class="built_in">top</span>();</span><br><span class="line">                right = <span class="keyword">new</span> <span class="built_in">VarExpression</span>(expStr[++i]);</span><br><span class="line">                expStack.<span class="built_in">push</span>(<span class="keyword">new</span> <span class="built_in">SubExpression</span>(left, right));</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">default</span>:</span><br><span class="line">                <span class="comment">// 变量表达式</span></span><br><span class="line">                expStack.<span class="built_in">push</span>(<span class="keyword">new</span> <span class="built_in">VarExpression</span>(expStr[i]));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">   </span><br><span class="line">    Expression* expression = expStack.<span class="built_in">top</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> expression;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">release</span><span class="params">(Expression* expression)</span></span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//释放表达式树的节点内存...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">const</span> <span class="keyword">char</span> * argv[])</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    string expStr = <span class="string">&quot;a+b-c+d-e&quot;</span>;</span><br><span class="line">    map&lt;<span class="keyword">char</span>, <span class="keyword">int</span>&gt; var;</span><br><span class="line">    var.<span class="built_in">insert</span>(<span class="built_in">make_pair</span>(<span class="string">&#x27;a&#x27;</span>,<span class="number">5</span>));</span><br><span class="line">    var.<span class="built_in">insert</span>(<span class="built_in">make_pair</span>(<span class="string">&#x27;b&#x27;</span>,<span class="number">2</span>));</span><br><span class="line">    var.<span class="built_in">insert</span>(<span class="built_in">make_pair</span>(<span class="string">&#x27;c&#x27;</span>,<span class="number">1</span>));</span><br><span class="line">    var.<span class="built_in">insert</span>(<span class="built_in">make_pair</span>(<span class="string">&#x27;d&#x27;</span>,<span class="number">6</span>));</span><br><span class="line">    var.<span class="built_in">insert</span>(<span class="built_in">make_pair</span>(<span class="string">&#x27;e&#x27;</span>,<span class="number">10</span>));</span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    Expression* expression= <span class="built_in">analyse</span>(expStr);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">int</span> result=expression-&gt;<span class="built_in">interpreter</span>(var);</span><br><span class="line">    </span><br><span class="line">    cout&lt;&lt;result&lt;&lt;endl;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">release</span>(expression);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="1214-结构"><a class="markdownIt-Anchor" href="#1214-结构"></a> 12.1.4 结构</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219124115233.png" alt="image-20211219124115233"></p>
<h3 id="1215-要点总结"><a class="markdownIt-Anchor" href="#1215-要点总结"></a> 12.1.5 要点总结</h3>
<ul>
<li>Interpreter模式的应用场合是Interpreter模式应用中的难点，只有满足“业务规则频繁变化，且类似的结构不断重复出现，并且容易抽象为语法规则的问题”才适合使用Interpreter模式.</li>
<li>使用Interpreter模式来表示文法规则，从而可以使用面向对象技巧来方便地“扩展”文法。</li>
<li>Interpreter模式比较适合简单的文法表示，对于复杂的文法表示，Interpreter模式会产生比较大的类层次结构，需要求助于语法分析器这样的标准工具。</li>
</ul>
<h1 id="13-设计模式总结"><a class="markdownIt-Anchor" href="#13-设计模式总结"></a> 13、设计模式总结</h1>
<h2 id="131-一个目标"><a class="markdownIt-Anchor" href="#131-一个目标"></a> 13.1 一个目标</h2>
<p>管理变化，提高复用！</p>
<h2 id="132-两种手段"><a class="markdownIt-Anchor" href="#132-两种手段"></a> 13.2 两种手段</h2>
<p>分解 vs. 抽象</p>
<h2 id="133-八大原则"><a class="markdownIt-Anchor" href="#133-八大原则"></a> 13.3 八大原则</h2>
<ul>
<li>依赖倒置原则（DIP)</li>
<li>开放封闭原则（OCP)</li>
<li>单一职责原则（SRP)</li>
<li>Liskov 替换原则（LSP)</li>
<li>接口隔离原则（ISP)</li>
<li>对象组合由于类继承</li>
<li>封装变化点</li>
<li>面向接口编程</li>
</ul>
<h2 id="134-重构技法"><a class="markdownIt-Anchor" href="#134-重构技法"></a> 13.4 重构技法</h2>
<ul>
<li>静态 -&gt; 动态</li>
<li>早绑定 -&gt; 晚绑定</li>
<li>继承 -&gt; 组合</li>
<li>编译时依赖 -&gt; 运行时依赖</li>
<li>紧耦合 -&gt; 松耦合</li>
</ul>
<h2 id="135-从封装变化角度对模式分类"><a class="markdownIt-Anchor" href="#135-从封装变化角度对模式分类"></a> 13.5 从封装变化角度对模式分类</h2>
<ul>
<li>组件协作：
<ul>
<li>Template Method</li>
<li>Observer / Event</li>
<li>Strategy</li>
</ul>
</li>
<li>单一职责：
<ul>
<li>Decorator</li>
<li>Bridge</li>
</ul>
</li>
<li>对象创建:
<ul>
<li>Factory Method</li>
<li>Abstract Factory</li>
<li>Prototype</li>
<li><em>Builder</em> 【注：不是很常用】</li>
</ul>
</li>
<li>对象性能：
<ul>
<li>Singleton</li>
<li>Flyweight</li>
</ul>
</li>
<li>接口隔离:
<ul>
<li>Façade</li>
<li>Proxy</li>
<li><em>Mediator</em>  【注：不是很常用】</li>
<li>Adapter</li>
</ul>
</li>
<li>状态变化：
<ul>
<li><em>Memento</em>  【注：不是很常用】</li>
<li>State</li>
</ul>
</li>
<li>数据结构：
<ul>
<li>Composite</li>
<li><em>Iterator</em>     【注：不是很常用】</li>
<li><em>Chain of Resposibility</em>   【注：不是很常用】</li>
</ul>
</li>
<li>行为变化：
<ul>
<li><em>Command</em>   【注：不是很常用】</li>
<li><em>Visitor</em>     【注：不是很常用】</li>
</ul>
</li>
<li>领域问题：
<ul>
<li><em>Interpreter</em>  【注：不是很常用】</li>
</ul>
</li>
</ul>
<h2 id="136-c-对象模型"><a class="markdownIt-Anchor" href="#136-c-对象模型"></a> 13.6 C++ 对象模型</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211219131404423.png" alt="image-20211219131404423"></p>
<p>继承和组合对象在C++对象模型上来说，都是B嵌入到A的内存中，且在A的内存的前面部分，A和B紧耦合，且B对象不具有灵活性，是不可变的；而第三种的组合一个指针就具有灵活性，指针指向的对象是可变的。</p>
<p>所有的模式最终都是通过指针指向多态对象来表达灵活性。</p>
<p>指针指向多态对象变成了松耦合对象模型的基础。</p>
<h2 id="137-关注变化点和稳定点"><a class="markdownIt-Anchor" href="#137-关注变化点和稳定点"></a> 13.7 关注变化点和稳定点</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211221145219708.png" alt="image-20211221145219708"></p>
<h2 id="138-什么时候不用模式"><a class="markdownIt-Anchor" href="#138-什么时候不用模式"></a> 13.8 什么时候不用模式</h2>
<ul>
<li>代码可读性很差时</li>
<li>需求理解还很浅时</li>
<li>变化没有显现时</li>
<li>不是系统的关键依赖点</li>
<li>项目没有复用价值时</li>
<li>项目将要发布时</li>
</ul>
<h2 id="139-经验之谈"><a class="markdownIt-Anchor" href="#139-经验之谈"></a> 13.9 经验之谈</h2>
<ul>
<li>不要为模式而模式</li>
<li>关注抽象类 &amp; 接口</li>
<li>理清变化点和稳定点</li>
<li>审视依赖关系</li>
<li>要有Framework 和 Application 的区隔思维</li>
<li>良好的设计是演化的结果</li>
</ul>
<h2 id="1310-设计模式成长之路"><a class="markdownIt-Anchor" href="#1310-设计模式成长之路"></a> 13.10 设计模式成长之路</h2>
<ul>
<li>“手中无剑，心中无剑”：见模式而不知</li>
<li>“手中有剑，心中无剑”：可以识别模式，作为应用开发人员使用模式</li>
<li>“手中有剑，心中有剑”：作为框架开发人员为应用设计某些模式</li>
<li>“手中无剑，心中有剑”：忘掉模式，只有原则</li>
</ul>


      <div>
        
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>


        
      </div>

    </div>

    
    
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Maureen
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://maureen-liu.gitee.io/p/9725cb23.html" title="C++设计模式">https://maureen-liu.gitee.io/p/9725cb23.html</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E6%9D%8E%E5%BB%BA%E5%BF%A0/" rel="tag"># 李建忠</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/p/e088fcc4.html" rel="prev" title="C++内存管理">
      <i class="fa fa-chevron-left"></i> C++内存管理
    </a></div>
      <div class="post-nav-item">
    <a href="/p/ae8b63c8.html" rel="next" title="C++STL标准库与泛型编程">
      C++STL标准库与泛型编程 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>
        
      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#1-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%AE%80%E4%BB%8B"><span class="nav-text"> 1、设计模式简介</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#11-%E7%9B%AE%E6%A0%87"><span class="nav-text"> 1.1 目标</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-%E4%BB%80%E4%B9%88%E6%98%AF%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 1.2 什么是设计模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13-gof%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 1.3 GOF设计模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-%E4%BB%8E%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%B0%88%E8%B5%B7"><span class="nav-text"> 1.4 从面向对象谈起</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="nav-text"> 1.5 深入理解面向对象</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#16-%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E5%9B%BA%E6%9C%89%E7%9A%84%E5%A4%8D%E6%9D%82%E6%80%A7"><span class="nav-text"> 1.6 软件设计固有的复杂性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#17-%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E5%A4%8D%E6%9D%82%E7%9A%84%E6%A0%B9%E6%9C%AC%E5%8E%9F%E5%9B%A0"><span class="nav-text"> 1.7 软件设计复杂的根本原因</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#18-%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%E5%A4%8D%E6%9D%82%E6%80%A7"><span class="nav-text"> 1.8 如何解决复杂性？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#19-%E7%BB%93%E6%9E%84%E5%8C%96-vs-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="nav-text"> 1.9 结构化 VS. 面向对象</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#110-%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E7%9A%84%E7%9B%AE%E6%A0%87"><span class="nav-text"> 1.10 软件设计的目标</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#2-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99"><span class="nav-text"> 2、面向对象设计原则</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#21-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1%E4%B8%BA%E4%BB%80%E4%B9%88"><span class="nav-text"> 2.1 面向对象设计，为什么？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#22-%E9%87%8D%E6%96%B0%E8%AE%A4%E8%AF%86%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="nav-text"> 2.2 重新认识面向对象</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#23-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99"><span class="nav-text"> 2.3 面向对象设计原则</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#231-%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99dip"><span class="nav-text"> 2.3.1 依赖倒置原则（DIP)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#232-%E5%BC%80%E6%94%BE%E5%B0%81%E9%97%AD%E5%8E%9F%E5%88%99ocp"><span class="nav-text"> 2.3.2 开放封闭原则（OCP）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#233-%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99srp"><span class="nav-text"> 2.3.3 单一职责原则（SRP)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#234-liskov-%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99lsp"><span class="nav-text"> 2.3.4 Liskov 替换原则（LSP)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#235-%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99isp"><span class="nav-text"> 2.3.5 接口隔离原则（ISP)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#236-%E4%BC%98%E5%85%88%E4%BD%BF%E7%94%A8%E5%AF%B9%E8%B1%A1%E7%BB%84%E5%90%88%E8%80%8C%E4%B8%8D%E6%98%AF%E7%B1%BB%E7%BB%A7%E6%89%BF"><span class="nav-text"> 2.3.6 优先使用对象组合，而不是类继承</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#237-%E5%B0%81%E8%A3%85%E5%8F%98%E5%8C%96%E7%82%B9"><span class="nav-text"> 2.3.7 封装变化点</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#238-%E9%92%88%E5%AF%B9%E6%8E%A5%E5%8F%A3%E7%BC%96%E7%A8%8B%E8%80%8C%E4%B8%8D%E6%98%AF%E9%92%88%E5%AF%B9%E5%AE%9E%E7%8E%B0%E7%BC%96%E7%A8%8B"><span class="nav-text"> 2.3.8 针对接口编程，而不是针对实现编程</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#24-%E9%9D%A2%E5%90%91%E6%8E%A5%E5%8F%A3%E8%AE%BE%E8%AE%A1"><span class="nav-text"> 2.4 面向接口设计</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#25-%E4%BB%A5%E5%8F%B2%E4%B8%BA%E9%89%B4"><span class="nav-text"> 2.5 以史为鉴</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#26-%E5%B0%86%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99%E6%8F%90%E5%8D%87%E4%B8%BA%E8%AE%BE%E8%AE%A1%E7%BB%8F%E9%AA%8C"><span class="nav-text"> 2.6 将设计原则提升为设计经验</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#3-%E6%A8%A1%E5%BC%8F%E7%9A%84%E5%88%86%E7%B1%BB"><span class="nav-text"> 3、模式的分类</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#31-gof-23-%E6%A8%A1%E5%BC%8F%E5%88%86%E7%B1%BB"><span class="nav-text"> 3.1 GOF-23 模式分类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#32-%E4%BB%8E%E5%B0%81%E8%A3%85%E5%8F%98%E5%8C%96%E8%A7%92%E5%BA%A6%E5%AF%B9%E6%A8%A1%E5%BC%8F%E5%88%86%E7%B1%BB"><span class="nav-text"> 3.2 从封装变化角度对模式分类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#33-%E9%87%8D%E6%9E%84%E8%8E%B7%E5%BE%97%E6%A8%A1%E5%BC%8F-refactoring-to-patterns"><span class="nav-text"> 3.3 重构获得模式 Refactoring to Patterns</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#34-%E6%8E%A8%E8%8D%90%E5%9B%BE%E4%B9%A6"><span class="nav-text"> 3.4 推荐图书</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#35-%E9%87%8D%E6%9E%84%E5%85%B3%E9%94%AE%E6%8A%80%E6%B3%95"><span class="nav-text"> 3.5 重构关键技法</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#4-%E7%BB%84%E4%BB%B6%E5%8D%8F%E4%BD%9C%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 4、&quot;组件协作&quot;模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#41-template-method%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 4.1 Template Method模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#411-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 4.1.1 动机(Motivation)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#412-%E7%BB%93%E6%9E%84%E5%8C%96%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E6%B5%81%E7%A8%8B"><span class="nav-text"> 4.1.2 结构化软件设计流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#413-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E6%B5%81%E7%A8%8B"><span class="nav-text"> 4.1.3 面向对象软件设计流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#414-%E6%97%A9%E7%BB%91%E5%AE%9A%E4%B8%8E%E6%99%9A%E7%BB%91%E5%AE%9A"><span class="nav-text"> 4.1.4 早绑定与晚绑定</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#415-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 4.1.5 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#416-%E7%BB%93%E6%9E%84"><span class="nav-text"> 4.1.6 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#417-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 4.1.7 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#42-strategy-%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 4.2 Strategy 策略模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#421-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 4.2.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#422-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 4.2.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#423-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 4.2.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#424-%E7%BB%93%E6%9E%84"><span class="nav-text"> 4.2.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#425-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 4.2.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#43-observer-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 4.3 Observer 观察者模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#431-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 4.3.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#432-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 4.3.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#433-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 4.3.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#433-%E7%BB%93%E6%9E%84"><span class="nav-text"> 4.3.3 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#435-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 4.3.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#5-%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 5、&quot;单一职责&quot;模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#51-decorator-%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 5.1 Decorator 装饰模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#511-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 5.1.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#512-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 5.1.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#513-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 5.1.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#514-%E7%BB%93%E6%9E%84structure"><span class="nav-text"> 5.1.4 结构（Structure)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#515-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 5.1.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#52-bridge-%E6%A1%A5%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 5.2 Bridge 桥模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#521-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 5.2.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#522-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 5.2.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#523-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 5.2.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#524-%E7%BB%93%E6%9E%84structure"><span class="nav-text"> 5.2.4 结构（Structure）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#525-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 5.2.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#6-%E5%AF%B9%E8%B1%A1%E5%88%9B%E5%BB%BA%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 6、&quot;对象创建&quot;模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#61-factory-method-%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95"><span class="nav-text"> 6.1 Factory Method 工厂方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#611-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 6.1.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#612-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 6.1.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#613-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 6.1.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#614-%E7%BB%93%E6%9E%84"><span class="nav-text"> 6.1.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#615-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 6.1.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#62-abstract-factory-%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82"><span class="nav-text"> 6.2 Abstract Factory 抽象工厂</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#621-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 6.2.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#622-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 6.2.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#623-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 6.2.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#624-%E7%BB%93%E6%9E%84"><span class="nav-text"> 6.2.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#625-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 6.2.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#63-prototype-%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 6.3 Prototype 原型模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#631-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 6.3.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#632-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 6.3.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#633-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 6.3.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#634-%E7%BB%93%E6%9E%84"><span class="nav-text"> 6.3.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#635-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 6.3.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#64-builder-%E6%9E%84%E5%BB%BA%E5%99%A8"><span class="nav-text"> 6.4 Builder 构建器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#641-%E5%8A%A8%E6%9C%BA-motivation"><span class="nav-text"> 6.4.1 动机 (Motivation)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#642-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 6.4.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#643-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 6.4.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#644-%E7%BB%93%E6%9E%84"><span class="nav-text"> 6.4.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#645-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 6.4.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#7-%E5%AF%B9%E8%B1%A1%E6%80%A7%E8%83%BD%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 7、“对象性能”模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#71-singleton-%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 7.1 Singleton 单例模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#711-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 7.1.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#712-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 7.1.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#713-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 7.1.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#714-%E7%BB%93%E6%9E%84"><span class="nav-text"> 7.1.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#715-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 7.1.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#72-flyweight-%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 7.2 Flyweight 享元模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#721-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 7.2.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#722-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 7.2.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#723-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 7.2.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#724-%E7%BB%93%E6%9E%84"><span class="nav-text"> 7.2.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#715-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93-2"><span class="nav-text"> 7.1.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#8-%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 8、“接口隔离”模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#81-facede-%E9%97%A8%E9%9D%A2%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 8.1 Facede 门面模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#811-%E7%B3%BB%E7%BB%9F%E9%97%B4%E8%80%A6%E5%90%88%E7%9A%84%E5%A4%8D%E6%9D%82%E5%BA%A6"><span class="nav-text"> 8.1.1 系统间耦合的复杂度</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#812-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 8.1.2 动机（Motivation)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#813-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 8.1.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#814-%E7%BB%93%E6%9E%84"><span class="nav-text"> 8.1.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#815-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 8.1.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#82-proxy-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 8.2 Proxy 代理模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#821-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 8.2.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#822-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 8.2.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#823-%E7%BB%93%E6%9E%84"><span class="nav-text"> 8.2.3 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#824-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 8.2.4 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#825-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 8.2.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#83-adapter-%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 8.3 Adapter 适配器模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#831-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 8.3.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#832-%E6%88%91%E4%BB%AC%E8%BA%AB%E8%BE%B9%E7%9A%84adapter"><span class="nav-text"> 8.3.2 我们身边的Adapter</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#833-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 8.3.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#834-%E7%BB%93%E6%9E%84"><span class="nav-text"> 8.3.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#835-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 8.3.5 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#836-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 8.3.6 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#84-mediator-%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 8.4 Mediator 中介者模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#841-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 8.4.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#842-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 8.4.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#843-%E7%BB%93%E6%9E%84"><span class="nav-text"> 8.4.3 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#844-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 8.4.4 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#9-%E7%8A%B6%E6%80%81%E5%8F%98%E5%8C%96%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 9、“状态变化”模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#91-state%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 9.1 State状态模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#911-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 9.1.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#912-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 9.1.2 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#913-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 9.1.3 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#914-%E7%BB%93%E6%9E%84"><span class="nav-text"> 9.1.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#915-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 9.1.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#92-memento-%E5%A4%87%E5%BF%98%E5%BD%95"><span class="nav-text"> 9.2 Memento 备忘录</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#921-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 9.2.1 动机（Motivation）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#922-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 9.2.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#923-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 9.2.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#924-%E7%BB%93%E6%9E%84"><span class="nav-text"> 9.2.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#925-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 9.2.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#10-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 10、“数据结构”模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#101-composite%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 10.1 Composite模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1011-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 10.1.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1012-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 10.1.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1013-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 10.1.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1013-%E7%BB%93%E6%9E%84"><span class="nav-text"> 10.1.3 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1014-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 10.1.4 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#102-iterator%E8%BF%AD%E4%BB%A3%E5%99%A8"><span class="nav-text"> 10.2 Iterator迭代器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1021-%E5%8A%A8%E6%9C%BAmotivation"><span class="nav-text"> 10.2.1 动机（Motivation)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1022-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 10.2.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1023-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 10.2.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1024-%E7%BB%93%E6%9E%84"><span class="nav-text"> 10.2.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1024-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 10.2.4 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#103-chain-of-responsibility%E8%81%8C%E8%B4%A3%E9%93%BE"><span class="nav-text"> 10.3  Chain of Responsibility职责链</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1031-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 10.3.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1032-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 10.3.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1033-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 10.3.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1034-%E7%BB%93%E6%9E%84"><span class="nav-text"> 10.3.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1034-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 10.3.4 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#11-%E8%A1%8C%E4%B8%BA%E5%8F%98%E5%8C%96%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 11、“行为变化”模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#111-command-%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 11.1 Command 命令模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1111-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 11.1.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1112-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 11.1.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1113-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 11.1.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1114-%E7%BB%93%E6%9E%84"><span class="nav-text"> 11.1.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1115-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 11.1.5 要点总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#112-visitor%E8%AE%BF%E9%97%AE%E5%99%A8"><span class="nav-text"> 11.2 Visitor访问器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1121-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 11.2.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1122-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 11.2.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1123-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 11.2.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1124-%E7%BB%93%E6%9E%84"><span class="nav-text"> 11.2.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1125-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 11.2.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#12-%E9%A2%86%E5%9F%9F%E8%A7%84%E5%88%99%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 12、“领域规则”模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#121-interpreter%E8%A7%A3%E6%9E%90%E5%99%A8"><span class="nav-text"> 12.1 Interpreter解析器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1211-%E5%8A%A8%E6%9C%BA"><span class="nav-text"> 12.1.1 动机</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1212-%E6%A8%A1%E5%BC%8F%E5%AE%9A%E4%B9%89"><span class="nav-text"> 12.1.2 模式定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1213-%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 12.1.3 代码示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1214-%E7%BB%93%E6%9E%84"><span class="nav-text"> 12.1.4 结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1215-%E8%A6%81%E7%82%B9%E6%80%BB%E7%BB%93"><span class="nav-text"> 12.1.5 要点总结</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#13-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%80%BB%E7%BB%93"><span class="nav-text"> 13、设计模式总结</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#131-%E4%B8%80%E4%B8%AA%E7%9B%AE%E6%A0%87"><span class="nav-text"> 13.1 一个目标</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#132-%E4%B8%A4%E7%A7%8D%E6%89%8B%E6%AE%B5"><span class="nav-text"> 13.2 两种手段</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#133-%E5%85%AB%E5%A4%A7%E5%8E%9F%E5%88%99"><span class="nav-text"> 13.3 八大原则</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#134-%E9%87%8D%E6%9E%84%E6%8A%80%E6%B3%95"><span class="nav-text"> 13.4 重构技法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#135-%E4%BB%8E%E5%B0%81%E8%A3%85%E5%8F%98%E5%8C%96%E8%A7%92%E5%BA%A6%E5%AF%B9%E6%A8%A1%E5%BC%8F%E5%88%86%E7%B1%BB"><span class="nav-text"> 13.5 从封装变化角度对模式分类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#136-c-%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B"><span class="nav-text"> 13.6 C++ 对象模型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#137-%E5%85%B3%E6%B3%A8%E5%8F%98%E5%8C%96%E7%82%B9%E5%92%8C%E7%A8%B3%E5%AE%9A%E7%82%B9"><span class="nav-text"> 13.7 关注变化点和稳定点</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#138-%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E4%B8%8D%E7%94%A8%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 13.8 什么时候不用模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#139-%E7%BB%8F%E9%AA%8C%E4%B9%8B%E8%B0%88"><span class="nav-text"> 13.9 经验之谈</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1310-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%88%90%E9%95%BF%E4%B9%8B%E8%B7%AF"><span class="nav-text"> 13.10 设计模式成长之路</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->
     
      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Maureen"
      src="/images/stan.jpeg">
  <p class="site-author-name" itemprop="name">Maureen</p>
  <div class="site-description" itemprop="description">心之所向，素履以往</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">7</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">2</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/maureenLiu" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;maureenLiu" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://blog.csdn.net/u011386173?spm=1000.2115.3001.5343" title="CSDN → https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011386173?spm&#x3D;1000.2115.3001.5343" rel="noopener" target="_blank"><i class="crosshairs fa-fw"></i>CSDN</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:maureen@qq.com" title="E-Mail → mailto:maureen@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

        <div id="music163player"> 
            <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&id=1475596788&auto=1&height=66"></iframe> 
        </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2021 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Maureen</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">307k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span class="post-meta-item-text">站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">4:39</span>
</div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : false,
      notify     : false,
      appId      : '7A7ruXkEvS4VKjoTaajLunbw-9Nh9j0Va',
      appKey     : 'E4svxhhfVsrC9eCyM8YfT8uq',
      placeholder: "Just go go",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : false,
      lang       : 'zh-cn' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>

<!-- 页面点击小红心 -->
<script type="text/javascript" src="/js/clicklove.js"></script>
